home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / kernel / proc / procMigrate.c < prev    next >
C/C++ Source or Header  |  1992-12-18  |  80KB  |  2,889 lines

  1. /* 
  2.  * procMigrate.c --
  3.  *
  4.  *    Routines for process migration.  These provide the system
  5.  *    call interface to initiate migration and routines to transfer
  6.  *    data from the host on which the process is currently executing
  7.  *    to the host to which it is migrating.  The routines that accept
  8.  *    this data are in procRemote.c.  
  9.  *
  10.  * Copyright 1986, 1988, 1989 Regents of the University of California
  11.  * Permission to use, copy, modify, and distribute this
  12.  * software and its documentation for any purpose and without
  13.  * fee is hereby granted, provided that the above copyright
  14.  * notice appear in all copies.  The University of California
  15.  * makes no representations about the suitability of this
  16.  * software for any purpose.  It is provided "as is" without
  17.  * express or implied warranty.
  18.  */
  19.  
  20. #ifndef lint
  21. static char rcsid[] = "$Header: /cdrom/src/kernel/Cvsroot/kernel/proc/procMigrate.c,v 9.36 92/06/01 14:39:23 kupfer Exp $ SPRITE (Berkeley)";
  22. #endif /* not lint */
  23.  
  24.  
  25. #include <sprite.h>
  26. #include <mach.h>
  27. #include <proc.h>
  28. #include <procInt.h>
  29. #include <procMigrate.h>
  30. #include <migrate.h>
  31. #include <migVersion.h>
  32. #include <fs.h>
  33. #include <stdlib.h>
  34. #include <string.h>
  35. #include <sig.h>
  36. #include <spriteTime.h>
  37. #include <trace.h>
  38. #include <list.h>
  39. #include <byte.h>
  40. #include <vm.h>
  41. #include <sys.h>
  42. #include <dbg.h>
  43. #include <rpc.h>
  44. #include <prof.h>
  45. #include <sched.h>
  46. #include <sync.h>
  47. #include <sysSysCall.h>
  48. #include <timer.h>
  49. #include <stdio.h>
  50. #include <bstring.h>
  51. #include <recov.h>
  52.  
  53. Sync_Condition    migrateCondition;
  54. Sync_Condition    evictCondition;
  55. static    Sync_Lock    migrateLock = Sync_LockInitStatic("Proc:migrateLock");
  56. #define    LOCKPTR &migrateLock
  57. static  Time        timeEvictionStarted;
  58.  
  59. int proc_MigDebugLevel = 2;
  60.  
  61. Trace_Header proc_TraceHeader;
  62. Trace_Header *proc_TraceHdrPtr = (Trace_Header *)NIL;
  63. Boolean proc_DoTrace = FALSE;
  64. Boolean proc_DoCallTrace = FALSE;
  65.  
  66. /*
  67.  * Allocate variables and structures relating to statistics.
  68.  * Updating variables is done under a monitor.  Currently, each update
  69.  * is typically done via a monitored procedure call, though it may be
  70.  * preferable to in-line the monitors (if this is permissible at some point)
  71.  * or combine multiple operations in a single procedure.
  72.  * Some of the statistics are kept even in CLEAN kernels because they affect
  73.  * the kernel's notion of whether eviction is necessary.  Also, the timing
  74.  * statistics are useful for benchmarking CLEAN kernels.   Things that are
  75.  * purely for statistics gathering are conditioned on CLEAN as well as
  76.  * proc_MigDoStats.
  77.  */  
  78. Boolean proc_MigDoStats = TRUE;
  79. Proc_MigStats proc_MigStats;
  80.  
  81. /*
  82.  * True if we should convert a SIG_DEBUG into a SIG_KILL for migrated
  83.  * processes.
  84.  */
  85. Boolean proc_KillMigratedDebugs = TRUE;
  86.  
  87. int proc_AllowMigrationState = PROC_MIG_ALLOW_DEFAULT;
  88.  
  89. /*
  90.  * Declare some variables from corresponding constants.  This permits
  91.  * them to be modified using the debugger or mainHook.  
  92.  */
  93. int proc_MigrationVersion = PROC_MIGRATE_VERSION;
  94. static int statsVersion = PROC_MIG_STATS_VERSION;
  95.  
  96. /*
  97.  * Procedures internal to this file
  98.  */
  99.  
  100. static ReturnStatus GetProcEncapSize _ARGS_((Proc_ControlBlock *procPtr,
  101.                 int hostID, Proc_EncapInfo *infoPtr));
  102. static ReturnStatus EncapProcState _ARGS_((Proc_ControlBlock *procPtr,
  103.                 int hostID, Proc_EncapInfo *infoPtr,
  104.                 Address bufPtr));
  105. static ReturnStatus DeencapProcState _ARGS_((Proc_ControlBlock *procPtr,
  106.                 Proc_EncapInfo *infoPtr, Address bufPtr));
  107.  
  108. static void         AbortMigration _ARGS_((Proc_ControlBlock *procPtr));
  109.  
  110. static void         SuspendCallback _ARGS_((ClientData data,
  111.                 Proc_CallInfo *callInfoPtr));
  112.  
  113. /*
  114.  * Procedures for statistics gathering
  115.  */
  116. static ENTRY void    AddMigrateTime _ARGS_((Time time, unsigned int *totalPtr,
  117.                 unsigned int *squaredTotalPtr));
  118. static ENTRY void    AccessStats _ARGS_((Proc_MigStats *copyPtr));
  119. static ENTRY Boolean EvictionStarted _ARGS_((void));
  120. static ENTRY void    WaitForEviction _ARGS_((void));
  121. static ENTRY ReturnStatus WaitForMigration _ARGS_((void));
  122.  
  123.  
  124. #ifdef DEBUG
  125. int proc_MemDebug = 0;
  126. #endif /* DEBUG */
  127. /*
  128.  * Define the structure for keeping track of callbacks for migrating
  129.  * a process.  (This is done after procedure declarations since
  130.  * some things are static and we need the forward reference.)
  131.  *
  132.  * See the comments in Proc_MigrateTrap for further explanation.
  133.  */
  134. typedef struct {
  135.     ReturnStatus (*preFunc)();       /* function to call when initiating
  136.                       migration (returning size); should not
  137.                       have side-effects requiring further
  138.                       callback */
  139.     ReturnStatus (*encapFunc)();   /* function to call to encapsulate data */
  140.     ReturnStatus (*deencapFunc)(); /* function to call to deencapsulate
  141.                     data on other end */
  142.     ReturnStatus (*postFunc)();       /* function to call after migration
  143.                       completes or fails */
  144.     Proc_EncapToken token;       /* identifier to match encap and deencap
  145.                       functions between two hosts */
  146.     int whenNeeded;           /* flags defined below indicate when
  147.                       needed */
  148. } EncapCallback;
  149.  
  150. /*
  151.  * Flags for the whenNeeded field:
  152.  */
  153. #define MIG_ENCAP_MIGRATE 1
  154. #define MIG_ENCAP_EXEC 2
  155. #define MIG_ENCAP_ALWAYS (MIG_ENCAP_MIGRATE | MIG_ENCAP_EXEC)
  156. /*    
  157.  * Set up the functions to be called.
  158.  */
  159. static EncapCallback encapCallbacks[] = {
  160.     { GetProcEncapSize, EncapProcState, DeencapProcState, NULL,
  161.       PROC_MIG_ENCAP_PROC, MIG_ENCAP_ALWAYS},
  162.     { ProcExecGetEncapSize, ProcExecEncapState, ProcExecDeencapState,
  163.       ProcExecFinishMigration,
  164.       PROC_MIG_ENCAP_EXEC, MIG_ENCAP_EXEC},
  165. #ifdef notdef
  166.     { Vm_InitiateMigration, Vm_EncapState, Vm_DeencapState, Vm_FinishMigration,
  167.       PROC_MIG_ENCAP_VM, MIG_ENCAP_MIGRATE},
  168. #endif
  169.     { Vm_InitiateMigration, Vm_EncapState, Vm_DeencapState, NULL,
  170.       PROC_MIG_ENCAP_VM, MIG_ENCAP_MIGRATE},
  171.     { Fs_InitiateMigration, Fs_EncapFileState, Fs_DeencapFileState, NULL,
  172.       PROC_MIG_ENCAP_FS, MIG_ENCAP_ALWAYS},
  173.     { Mach_GetEncapSize, Mach_EncapState, Mach_DeencapState, NULL,
  174.       PROC_MIG_ENCAP_MACH, MIG_ENCAP_ALWAYS},
  175.     { Prof_GetEncapSize, Prof_EncapState, Prof_DeencapState, NULL,
  176.       PROC_MIG_ENCAP_PROF, MIG_ENCAP_ALWAYS},
  177.     { Sig_GetEncapSize, Sig_EncapState, Sig_DeencapState, NULL,
  178.       PROC_MIG_ENCAP_SIG, MIG_ENCAP_ALWAYS},
  179. };
  180.  
  181. #define BREAKS_KDBX
  182. #ifdef BREAKS_KDBX
  183. static struct {
  184.     char *preFunc;       /* name of function to call when initiating
  185.                       migration */
  186.     char *encapFunc;    /* name of function to call to encapsulate */
  187.     char *deencapFunc;    /* name of function to call to deencapsulate */
  188.     char *postFunc;    /* name of function to call when done */
  189. } callbackNames[] = {
  190.     { "GetProcEncapSize", "EncapProcState", "DeencapProcState", NULL},
  191.     { "ProcExecGetEncapSize", "ProcExecEncapState", "ProcExecDeencapState", "ProcExecFinishMigration"},
  192.     { "Vm_InitiateMigration", "Vm_EncapState", "Vm_DeencapState",
  193.       NULL},
  194.     { "Fs_InitiateMigration", "Fs_EncapFileState", "Fs_DeencapFileState",
  195.       "Fs_MigDone"},
  196.     { "Mach_InitiateMigration", "Mach_EncapState", "Mach_DeencapState", NULL},
  197.     { "Prof_InitiateMigration", "Prof_EncapState", "Prof_DeencapState", NULL},
  198.     { "Sig_InitiateMigration", "Sig_EncapState", "Sig_DeencapState", NULL}
  199. };
  200. #endif
  201.  
  202. /*
  203.  * Define a macro for squaring a time without automatically overflowing
  204.  * due to the large number of microseconds being multiplied.
  205.  * The square of (X + Y/1000000) is X^2 + 2XY/1000000 + Y^2/10^12.
  206.  * XXX not used -- switched to single integers as milliseconds.  
  207.  */
  208. #define SQUARE_TIME(time, squaredTime) \
  209.     squaredTime.seconds = time.seconds * time.seconds; \
  210.     squaredTime.microseconds = 2 * time.seconds * time.microseconds + \
  211.                              time.microseconds * time.microseconds / 1000000; \
  212.     while (squaredTime.microseconds > 1000000) { \
  213.     squaredTime.seconds++; \
  214.     squaredTime.microseconds -= 1000000; \
  215.     } \
  216.  
  217.  
  218.  
  219.  
  220. /*
  221.  *----------------------------------------------------------------------
  222.  *
  223.  * Proc_MigInit --
  224.  *
  225.  *    Initialize data structures relating to process migration.
  226.  *    This procedure is called at boot time.
  227.  *    Sets up statistics gathering and recovery code.
  228.  *
  229.  * Results:
  230.  *    None.
  231.  *
  232.  * Side effects:
  233.  *    Calls other initialization procedures.
  234.  *
  235.  *----------------------------------------------------------------------
  236.  */
  237.  
  238. void
  239. Proc_MigInit()
  240. {
  241.     AccessStats((Proc_MigStats *) NIL);
  242.     ProcRecovInit();
  243. }
  244.  
  245.  
  246.  
  247. /*
  248.  *----------------------------------------------------------------------
  249.  *
  250.  * Proc_Migrate --
  251.  *
  252.  *    Migrates a process to another workstation.  The process may be
  253.  *        PROC_MY_PID, PROC_ALL_PROCESSES, or a process ID.
  254.  *        PROC_ALL_PROCESSES implies evicting all foreign processes, in
  255.  *        which case the hostID is ignored.  The workstation may be
  256.  *        PROC_MIG_ANY or a particular workstation.  (For now, the
  257.  *        workstation argument must be a specific workstation.)
  258.  *
  259.  *     This procedure implements the system call by the same name.
  260.  *
  261.  * Results:
  262.  *    PROC_INVALID_PID -    the pid argument was illegal.
  263.  *    PROC_INVALID_NODE_ID -    the host argument was illegal.
  264.  *    GEN_NO_PERMISSION -    the user or process is not permitted to
  265.  *                migrate.
  266.  *    Other results may be returned from the VM and RPC modules.
  267.  *
  268.  * Side effects:
  269.  *    The specified process is migrated to another workstation.
  270.  *
  271.  *----------------------------------------------------------------------
  272.  */
  273.  
  274. ReturnStatus
  275. Proc_Migrate(pid, hostID)
  276.     Proc_PID pid;
  277.     int         hostID;
  278. {
  279.     register Proc_ControlBlock *procPtr;
  280.     ReturnStatus status;
  281.     Proc_TraceRecord record;
  282.     Boolean migrateSelf = FALSE;
  283.     int permMask;
  284.  
  285.     /*
  286.      * It is possible for a process to try to migrate onto the machine
  287.      * on which it is currently executing.
  288.      */
  289.  
  290.     if (hostID == rpc_SpriteID) {
  291.     return(SUCCESS);
  292.     }
  293.     
  294.     if (Proc_ComparePIDs(pid, PROC_ALL_PROCESSES)) {
  295.     procPtr = Proc_GetEffectiveProc();
  296.     if (procPtr->effectiveUserID != 0) {
  297.         return(GEN_NO_PERMISSION);
  298.     }
  299.     status = Proc_EvictForeignProcs();
  300.     return(status);
  301.     }
  302.     
  303.     if (hostID <= 0 || hostID > NET_NUM_SPRITE_HOSTS) {
  304.     return(GEN_INVALID_ARG);
  305.     }
  306.  
  307.     if (Proc_ComparePIDs(pid, PROC_MY_PID)) {
  308.     migrateSelf = TRUE;
  309.     procPtr = Proc_GetActualProc();
  310.     if (procPtr == (Proc_ControlBlock *) NIL) {
  311.         panic("Proc_Migrate: procPtr == NIL\n");
  312.     }
  313.     Proc_Lock(procPtr);
  314.     pid = procPtr->processID;
  315.     } else {
  316.     procPtr = Proc_LockPID(pid);
  317.     if (procPtr == (Proc_ControlBlock *) NIL) {
  318.         return (PROC_INVALID_PID);
  319.     }
  320.     }
  321.  
  322.  
  323.     if (proc_MigDebugLevel > 3) {
  324.     printf("Proc_Migrate: migrate process %x to host %d.\n",
  325.            procPtr->processID, hostID);
  326.     }
  327.  
  328.     /*
  329.      * Do some sanity checking.  
  330.      */
  331.     if ((procPtr->state == PROC_DEAD) || (procPtr->state == PROC_EXITING) ||
  332.     (procPtr->genFlags & PROC_DYING)) {
  333.     if (proc_MigDebugLevel > 3) {
  334.         printf("Proc_Migrate: process %x has exited.\n",
  335.                pid);
  336.     }
  337.     Proc_Unlock(procPtr);
  338.     return(PROC_INVALID_PID);
  339.     }
  340.     if (procPtr->state == PROC_MIGRATED) {
  341.     if (proc_MigDebugLevel > 1) {
  342.         printf("Proc_Migrate: process %x has already migrated.\n",
  343.                pid);
  344.     }
  345.     Proc_Unlock(procPtr);
  346.     return(PROC_INVALID_PID);
  347.     }
  348.     
  349.     if (procPtr->genFlags & PROC_FOREIGN) {
  350.     if (proc_MigDebugLevel > 0) {
  351.         printf("Proc_Migrate: process %x is foreign... can't migrate yet.\n",
  352.                procPtr->processID);
  353.     }
  354.     Proc_Unlock(procPtr);
  355.     return(PROC_INVALID_PID);
  356.     }
  357.     if (procPtr->genFlags & PROC_DONT_MIGRATE) {
  358.     if (proc_MigDebugLevel > 0) {
  359.         printf("Proc_Migrate: process %x is not allowed to migrate.\n",
  360.                pid);
  361.     }
  362.     Proc_Unlock(procPtr);
  363.     return(GEN_NO_PERMISSION);
  364.     }
  365.     
  366.     if (procPtr->argString == (char *) NIL) {
  367.     if (proc_MigDebugLevel > 0) {
  368.         printf("Proc_Migrate: process %x has no argument string: can't migrate.\n",
  369.                pid);
  370.     }
  371.     Proc_Unlock(procPtr);
  372.     return(PROC_INVALID_PID);
  373.     }
  374.     
  375.     if (procPtr->userID == PROC_SUPER_USER_ID) {
  376.     permMask = PROC_MIG_EXPORT_ROOT;
  377.     } else {
  378.     permMask = PROC_MIG_EXPORT_ALL;
  379.     }
  380.  
  381.     if ((proc_AllowMigrationState & permMask) != permMask) {
  382.     if (proc_MigDebugLevel > 0) {
  383.         printf("Proc_Migrate: user does not have permission to migrate.\n");
  384.     }
  385.     Proc_Unlock(procPtr);
  386.     return(GEN_NO_PERMISSION);
  387.     }
  388.     
  389. #ifndef CLEAN
  390.     if (proc_DoTrace && proc_MigDebugLevel > 0) {
  391.     record.processID = procPtr->processID;
  392.     record.flags = PROC_MIGTRACE_START | PROC_MIGTRACE_HOME;
  393.     record.info.filler = NIL;
  394.     Trace_Insert(proc_TraceHdrPtr, PROC_MIGTRACE_BEGIN_MIG,
  395.              (ClientData) &record);
  396.     }
  397. #endif /* CLEAN */
  398.    
  399.     /*
  400.      * Contact the remote workstation to establish communication and
  401.      * verify that migration is permissible.
  402.      */
  403.     
  404.     status = ProcInitiateMigration(procPtr, hostID);
  405.  
  406.  
  407.     if (status != SUCCESS) {
  408.     Proc_Unlock(procPtr);
  409. #ifndef CLEAN
  410.     if (proc_MigDoStats) {
  411.         PROC_MIG_INC_STAT(errors);
  412.     }
  413. #endif /* CLEAN */
  414.     return(status);
  415.     }
  416.  
  417.     
  418.     Proc_FlagMigration(procPtr, hostID, FALSE);
  419.  
  420.     Proc_Unlock(procPtr);
  421.  
  422.     /*
  423.      * If migrating another process, wait for it to migrate.
  424.      */
  425.     if (!migrateSelf) {
  426.     status = Proc_WaitForMigration(pid);
  427.     } else {
  428.     status = SUCCESS;
  429.     }
  430.  
  431.     /*
  432.      * Note: the "end migration" trace record is inserted by the MigrateTrap
  433.      * routine to get around the issue of waiting for oneself to migrate.
  434.      * (Otherwise, since we can't wait here for the current process to
  435.      * migrate -- only a different process -- we wouldn't be able to insert
  436.      * the trace record at the right time.)
  437.      */
  438.      
  439.     return(status);
  440. }
  441.  
  442.  
  443. /*
  444.  *----------------------------------------------------------------------
  445.  *
  446.  * Proc_MigrateTrap --
  447.  *
  448.  *    Transfer the state of a process once it has reached a state with no
  449.  *    relevant information on the kernel stack.  This is done following a
  450.  *    kernel call, when the process can migrate and immediately return
  451.  *    to user mode and there is no relevant information on the kernel
  452.  *    stack.  
  453.  *
  454.  * Results:
  455.  *    No value is returned.
  456.  *
  457.  * Side effects:
  458.  *    The process state is transferred by performing callbacks
  459.  *    to each module with state to transfer.
  460.  *
  461.  *----------------------------------------------------------------------
  462.  */
  463.  
  464. void
  465. Proc_MigrateTrap(procPtr)
  466.     register Proc_ControlBlock     *procPtr; /* The process being migrated */
  467. {
  468.     int hostID;            /* host to which it migrates */
  469.     ReturnStatus status = FAILURE;
  470.     Proc_TraceRecord record;
  471.     Boolean foreign = FALSE;
  472.     Boolean evicting = FALSE;
  473.     Address buffer;
  474.     Address bufPtr;
  475.     int bufSize;
  476.     register int i;
  477.     Proc_EncapInfo info[PROC_MIG_NUM_CALLBACKS];
  478.     Proc_EncapInfo *infoPtr;
  479.     ProcMigCmd cmd;
  480.     Proc_MigBuffer inBuf;
  481.     int failed;
  482.     Time startTime;
  483.     Time endTime;
  484.     Time timeDiff;
  485.     unsigned int *timePtr;
  486.     unsigned int *squaredTimePtr;
  487.     int whenNeeded;
  488.     Boolean exec;
  489.     Proc_PID pid;
  490.  
  491.     Proc_Lock(procPtr);
  492.  
  493.     if (procPtr->genFlags & PROC_FOREIGN) {
  494.     foreign = TRUE;
  495.     if (procPtr->migFlags & PROC_EVICTING) {
  496.         evicting = TRUE;
  497.     }
  498.     }
  499.     if (procPtr->genFlags & PROC_REMOTE_EXEC_PENDING) {
  500.     whenNeeded = MIG_ENCAP_EXEC;
  501.     exec = TRUE;
  502.     } else {
  503.     whenNeeded = MIG_ENCAP_MIGRATE;
  504.     exec = FALSE;
  505.     }
  506.     if (proc_MigDoStats) {
  507.     Timer_GetTimeOfDay(&startTime, (int *) NIL, (Boolean *) NIL);
  508.     }
  509.     pid = procPtr->processID;
  510.     if (proc_DoTrace && proc_MigDebugLevel > 1) {
  511.     record.processID = pid;
  512.     record.flags = PROC_MIGTRACE_START;
  513.     if (!foreign) {
  514.         record.flags |= PROC_MIGTRACE_HOME;
  515.     }
  516.     record.info.filler = NIL;
  517.     Trace_Insert(proc_TraceHdrPtr, PROC_MIGTRACE_MIGTRAP,
  518.              (ClientData) &record);
  519.     }
  520.    
  521.     procPtr->genFlags = (procPtr->genFlags 
  522.              & ~(PROC_MIG_PENDING | PROC_MIGRATION_DONE)
  523.              | PROC_MIGRATING);
  524.     
  525.     hostID = procPtr->peerHostID;
  526.     bufSize = 0;
  527.  
  528.     /*
  529.      * Go through the list of callbacks to generate the size of the buffer
  530.      * we'll need.  In unusual circumstances, a caller may return a status
  531.      * other than SUCCESS. In this case, the process should be continuable!
  532.      */
  533.     for (i = 0; i < PROC_MIG_NUM_CALLBACKS; i++) {
  534.     if (!(encapCallbacks[i].whenNeeded & whenNeeded)) {
  535.         continue;
  536.     }
  537.     infoPtr = &info[i];
  538.     infoPtr->token = encapCallbacks[i].token;
  539.     infoPtr->processed = 0;
  540.     infoPtr->special = 0;
  541.     if (proc_MigDebugLevel > 5) {
  542.         printf("Calling preFunc %d\n", i);
  543.     }
  544.     status = (*encapCallbacks[i].preFunc)(procPtr, hostID, infoPtr);
  545.     if (status == SUCCESS && infoPtr->special) {
  546.         /*
  547.          * This is where we'd like to handle special cases like shared
  548.          * memory processes.  For now, bail out.
  549.          */
  550.         status = GEN_NOT_IMPLEMENTED;
  551.     }
  552.     if (status != SUCCESS) {
  553.         printf("Warning: Proc_MigrateTrap: error returned by encapsulation procedure %s:\n\t%s.\n",
  554. #ifdef BREAKS_KDBX
  555.            callbackNames[i].preFunc,
  556. #else /* BREAKS_KDBX */
  557.            "(can't get name)", 
  558. #endif /* BREAKS_KDBX */
  559.            Stat_GetMsg(status));
  560.         if (exec) {
  561.         goto failure;
  562.         } else {
  563.         AbortMigration(procPtr);
  564.         }
  565.         return;
  566.     }
  567.     bufSize += infoPtr->size + sizeof(Proc_EncapInfo);
  568.     }
  569.     if (proc_MigDebugLevel > 5) {
  570.     printf("Buffer size is %d\n", bufSize);
  571.     }
  572.     buffer = malloc(bufSize);
  573.     if (proc_MigDebugLevel > 5) {
  574.     printf("past malloc\n", bufSize);
  575.     }
  576.     bufPtr = buffer;
  577.     failed = 0;
  578.  
  579.     /*
  580.      * This time, go through the list of callbacks to fill in the
  581.      * encapsulated data.  From this point on, failed indicates
  582.      * that the process will be killed.
  583.      */
  584.     for (i = 0; i < PROC_MIG_NUM_CALLBACKS; i++) {
  585.     if (!(encapCallbacks[i].whenNeeded & whenNeeded)) {
  586.         continue;
  587.     }
  588.     infoPtr = &info[i];
  589.     bcopy((Address) infoPtr, bufPtr, sizeof(Proc_EncapInfo));
  590.     bufPtr += sizeof(Proc_EncapInfo);
  591.     if (proc_MigDebugLevel > 5) {
  592.         printf("Calling encapFunc %d\n", i);
  593.     }
  594.     status = (*encapCallbacks[i].encapFunc)(procPtr, hostID, infoPtr,
  595.                         bufPtr);
  596. #ifdef lint
  597.     status = EncapProcState(procPtr, hostID, infoPtr, bufPtr);
  598.     status = ProcExecEncapState(procPtr, hostID, infoPtr, bufPtr);
  599.     status = Vm_EncapState(procPtr, hostID, infoPtr, bufPtr);
  600.     status = Fs_EncapFileState(procPtr, hostID, infoPtr, bufPtr);
  601.     status = Mach_EncapState(procPtr, hostID, infoPtr, bufPtr);
  602.     status = Prof_EncapState(procPtr, hostID, infoPtr, bufPtr);
  603.     status = Sig_EncapState(procPtr, hostID, infoPtr, bufPtr);
  604. #endif /* lint */
  605.     if (status != SUCCESS) {
  606.         printf("Warning: Proc_MigrateTrap: error returned by encapsulation procedure %s:\n\t%s.\n",
  607. #ifdef BREAKS_KDBX
  608.            callbackNames[i].encapFunc,
  609. #else /* BREAKS_KDBX */
  610.            "(can't get name)", 
  611. #endif /* BREAKS_KDBX */
  612.            Stat_GetMsg(status));
  613.         failed = 1;
  614.         break;
  615.     }
  616.     bufPtr += infoPtr->size;
  617.     infoPtr->processed = 1;
  618.     }
  619.  
  620.     Proc_Unlock(procPtr);
  621.     /*
  622.      * Send the encapsulated data in the buffer to the other host.  
  623.      */
  624.     if (!failed) {
  625.     /*
  626.      * Set up for the RPC.
  627.      */
  628.     cmd.command = PROC_MIGRATE_CMD_ENTIRE;
  629.     cmd.remotePid = procPtr->peerProcessID;
  630.     inBuf.size = bufSize;
  631.     inBuf.ptr = buffer;
  632.     if (proc_MigDoStats) {
  633.         Proc_MigAddToCounter((bufSize + 1023) / 1024, &proc_MigStats.varStats.rpcKbytes, &proc_MigStats.squared.rpcKbytes);
  634.     }
  635.  
  636.     if (proc_MigDebugLevel > 5) {
  637.         printf("Sending encapsulated state.\n");
  638.     }
  639.     status = ProcMigCommand(procPtr->peerHostID, &cmd, &inBuf,
  640.                 (Proc_MigBuffer *) NIL);
  641.  
  642.     if (status != SUCCESS) {
  643.         printf("Warning: Proc_MigrateTrap: error encountered sending encapsulated state:\n\t%s.\n",
  644.            Stat_GetMsg(status));
  645.         failed = 1;
  646.     }
  647.     }
  648.     /*
  649.      * Finally, go through the list of callbacks to clean up.  Only call
  650.      * routines that were processed last time (in the case of failure
  651.      * partway through).  Note that the process pointer is UNLOCKED
  652.      * during these callbacks (as well as the RPC to transfer state).
  653.      * This is primarily because Vm_FinishMigration is the only callback
  654.      * so far and it needs it unlocked, and we have to unlock for the rpc
  655.      * anyway so that we don't deadlock on the process once the migrated
  656.      * version resumes (a side effect of the RPC).
  657.      */
  658.     bufPtr = buffer;
  659.     for (i = 0; i < PROC_MIG_NUM_CALLBACKS; i++) {
  660.     if (!(encapCallbacks[i].whenNeeded & whenNeeded)) {
  661.         continue;
  662.     }
  663.     infoPtr = &info[i];
  664.     if (infoPtr->processed != 1) {
  665.         continue;
  666.     }
  667.     bufPtr += sizeof(Proc_EncapInfo);
  668.     if (encapCallbacks[i].postFunc != NULL) {
  669.         if (proc_MigDebugLevel > 5) {
  670.         printf("Calling postFunc %d\n", i);
  671.         }
  672.         status = (*encapCallbacks[i].postFunc)(procPtr, hostID, infoPtr,
  673.                            bufPtr, failed);
  674. #ifdef lint
  675.         status = Vm_FinishMigration(procPtr, hostID, infoPtr, bufPtr,
  676.                     failed);
  677. #endif /* lint */
  678.     }
  679.     if (status != SUCCESS) {
  680.         failed = 1;
  681.     }
  682.     bufPtr += infoPtr->size;
  683.     }
  684.     free(buffer);
  685.  
  686.     if (failed) {
  687.     goto failure;
  688.     }
  689.  
  690.     Proc_Lock(procPtr);
  691.  
  692.     procPtr->genFlags = (procPtr->genFlags
  693.              & ~(PROC_REMOTE_EXEC_PENDING| PROC_MIG_ERROR)
  694.              | PROC_MIGRATION_DONE);
  695.     Proc_Unlock(procPtr);
  696.  
  697.  
  698.     /*
  699.      * Tell the other host to resume the process.
  700.      */
  701.     cmd.command = PROC_MIGRATE_CMD_RESUME;
  702.     cmd.remotePid = procPtr->peerProcessID;
  703.  
  704.     if (proc_MigDebugLevel > 5) {
  705.     printf("Issuing resume command.\n");
  706.     }
  707.     status = ProcMigCommand(procPtr->peerHostID, &cmd, (Proc_MigBuffer *) NIL,
  708.                 (Proc_MigBuffer *) NIL);
  709.  
  710.     if (status != SUCCESS) {
  711.     printf("Warning: Proc_MigrateTrap: error encountered resuming process:\n\t%s.\n",
  712.            Stat_GetMsg(status));
  713.     goto failure;
  714.     }
  715.  
  716.     /*
  717.      * If not migrating back home, note the dependency on the other host.
  718.      * Otherwise, forget the dependency after eviction.
  719.      */
  720.     if (!foreign) {
  721.     ProcMigAddDependency(procPtr->processID, procPtr->peerProcessID);
  722.     } else {
  723.     ProcMigRemoveDependency(procPtr->processID, TRUE);
  724.     }
  725.  
  726.  
  727.     /*
  728.      * Anyone waiting to send a signal to the process should wait until
  729.      * this point so the process is executing on the other host.  On the
  730.      * other hand, some code wants to wait until the process has finished
  731.      * context switching.  So, clear the "evicting" flag, but don't yet 
  732.      * clear the "migrating" flag or wake up processes waiting for the
  733.      * migration to complete.
  734.      */
  735.     Proc_Lock(procPtr);
  736.     procPtr->migFlags &= ~PROC_EVICTING;
  737.     Proc_Unlock(procPtr);
  738.  
  739.     if (proc_DoTrace && proc_MigDebugLevel > 1) {
  740.     record.flags = (foreign ? 0 : PROC_MIGTRACE_HOME);
  741.     Trace_Insert(proc_TraceHdrPtr, PROC_MIGTRACE_MIGTRAP,
  742.              (ClientData) &record);
  743.     }
  744.  
  745.     if (proc_MigDoStats) {
  746.     Timer_GetTimeOfDay(&endTime, (int *) NIL, (Boolean *) NIL);
  747.     Time_Subtract(endTime, startTime, &timeDiff);
  748.     if (whenNeeded == MIG_ENCAP_MIGRATE) {
  749.         if (evicting) {
  750.         timePtr = &proc_MigStats.varStats.timeToEvict;
  751.         squaredTimePtr = &proc_MigStats.squared.timeToEvict;
  752.         } else {
  753.         timePtr = &proc_MigStats.varStats.timeToMigrate;
  754.         squaredTimePtr = &proc_MigStats.squared.timeToMigrate;
  755.         }
  756.     } else {
  757.         timePtr = &proc_MigStats.varStats.timeToExec;
  758.         squaredTimePtr = &proc_MigStats.squared.timeToExec;
  759.     }
  760.     AddMigrateTime(timeDiff, timePtr, squaredTimePtr);
  761.     }
  762.     if (proc_DoTrace && proc_MigDebugLevel > 0 && !foreign) {
  763.     record.processID = pid;
  764.     record.flags = PROC_MIGTRACE_HOME;
  765.     record.info.filler = NIL;
  766.     Trace_Insert(proc_TraceHdrPtr, PROC_MIGTRACE_END_MIG,
  767.              (ClientData) &record);
  768.     }
  769.  
  770.     /*
  771.      * All aboard!
  772.      * 
  773.      * Check for asynchronous errors coming in after we resumed on the other
  774.      * host.  If there aren't any, mark the migration as finally really 
  775.      * being complete and wake up any processes that might be waiting for
  776.      * the migration to complete.
  777.      */
  778.     Proc_Lock(procPtr);
  779.     if (procPtr->genFlags & PROC_MIG_ERROR) {
  780.     Proc_Unlock(procPtr);
  781.     goto failure;
  782.     }
  783.  
  784.     procPtr->genFlags &= ~PROC_MIGRATING;
  785.     ProcMigWakeupWaiters();
  786.  
  787.     if (foreign) {
  788.     PROC_MIG_DEC_STAT(foreign);
  789.     if (evicting ||
  790.         (proc_MigStats.foreign == 0 &&
  791.          proc_MigStats.evictionsInProgress != 0)) {
  792.         ProcMigEvictionComplete();
  793.     }
  794. #ifndef CLEAN
  795.     if (proc_MigDoStats) {
  796.         if (!evicting) {
  797.         PROC_MIG_INC_STAT(migrationsHome);
  798.         }
  799.     }
  800. #endif /* CLEAN */
  801.     Proc_Unlock(procPtr);
  802.     ProcExitProcess(procPtr, -1, -1, -1, TRUE);
  803.     } else {
  804. #ifndef CLEAN
  805.     if (proc_MigDoStats) {
  806.         PROC_MIG_INC_STAT(remote);
  807.         PROC_MIG_INC_STAT(exports);
  808.         if (exec) {
  809.         PROC_MIG_INC_STAT(execs);
  810.         }
  811.         PROC_MIG_INC_STAT(hostCounts[hostID]);
  812.     }
  813. #endif /* CLEAN */
  814.     Proc_UnlockAndSwitch(procPtr, PROC_MIGRATED);
  815.     }
  816.     panic("Proc_MigrateTrap: returned from context switch.\n");
  817.     return;
  818.  
  819.  failure:
  820.     /*
  821.      * If the process hit some error (e.g., the remote host rebooted), or
  822.      * the processes exited on the other host, we don't bother sending an 
  823.      * RPC to the other host.
  824.      */
  825.     Proc_Lock(procPtr);
  826.     if (!(procPtr->genFlags & PROC_MIG_ERROR)) {
  827.     ProcMigKillRemoteCopy((ClientData) procPtr->peerProcessID,
  828.         (Proc_CallInfo *) NIL);
  829.     }
  830.     procPtr->genFlags &= ~(PROC_MIGRATING|PROC_REMOTE_EXEC_PENDING|
  831.                PROC_MIG_ERROR|PROC_MIGRATION_DONE);
  832.     procPtr->migFlags &= ~PROC_EVICTING;
  833.     ProcMigWakeupWaiters();
  834.     if (proc_DoTrace && proc_MigDebugLevel > 0 && !foreign) {
  835.     record.processID = pid;
  836.     record.flags = PROC_MIGTRACE_HOME;
  837.     record.info.filler = NIL;
  838.     Trace_Insert(proc_TraceHdrPtr, PROC_MIGTRACE_END_MIG,
  839.              (ClientData) &record);
  840.     }
  841. #ifndef CLEAN
  842.     if (proc_MigDoStats) {
  843.     PROC_MIG_INC_STAT(errors);
  844.     }
  845. #endif /* CLEAN */
  846.     /*
  847.      * The migration failed, so exit.  By calling the exit routine
  848.      * directly we avoid problems that might result from having no
  849.      * VM, etc.
  850.      */
  851.     Proc_Unlock(procPtr);
  852.     Proc_ExitInt(PROC_TERM_DESTROYED, (int) PROC_NO_PEER, 0);
  853. }
  854.  
  855. /*
  856.  *----------------------------------------------------------------------
  857.  *
  858.  * AbortMigration --
  859.  *
  860.  *    Undo a migration at a point when the process can still be
  861.  *    continued on the local host.  This is only true when migrating
  862.  *    a running process, not when execing a new image, since we can't
  863.  *    recover from that.
  864.  *
  865.  * Results:
  866.  *    None.
  867.  *
  868.  * Side effects:
  869.  *    If the process is currently local, an RPC is sent to the remote host.
  870.  *
  871.  *----------------------------------------------------------------------
  872.  */
  873. static void
  874. AbortMigration(procPtr)
  875.     Proc_ControlBlock *procPtr; /* ptr to process control block */
  876. {
  877.     if (!(procPtr->genFlags & PROC_FOREIGN)) {
  878.     ProcMigKillRemoteCopy((ClientData) procPtr->peerProcessID,
  879.         (Proc_CallInfo *) NIL);
  880.     procPtr->peerProcessID = NIL;
  881.     procPtr->peerHostID = NIL;
  882.     }
  883.     procPtr->genFlags &= ~PROC_MIGRATING;
  884.     procPtr->sigPendingMask &= ~Sig_NumberToMask(SIG_MIGRATE_TRAP);
  885.     Proc_Unlock(procPtr);
  886.     ProcMigWakeupWaiters();
  887. }
  888.  
  889. /*
  890.  *----------------------------------------------------------------------
  891.  *
  892.  * ProcMigReceiveProcess --
  893.  *
  894.  *    Receive the encapsulated state of a process from another host
  895.  *    and deencapsulate it by calling the appropriate callback routines.
  896.  *    If deencapsulation succeeds, resume the migrated process.
  897.  *
  898.  * Results:
  899.  *    A ReturnStatus indicates whether deencapsulation succeeds.  If
  900.  *     a module returns an error, the first error is returned and the
  901.  *    rest of the state is not deencapsulated.
  902.  *
  903.  * Side effects:
  904.  *    The process is resumed on this host.
  905.  *
  906.  *----------------------------------------------------------------------
  907.  */
  908.  
  909. /* ARGSUSED */
  910. ReturnStatus
  911. ProcMigReceiveProcess(cmdPtr, procPtr, inBufPtr, outBufPtr)
  912.     ProcMigCmd *cmdPtr;/* contains ID of process on this host */
  913.     Proc_ControlBlock *procPtr; /* ptr to process control block */
  914.     Proc_MigBuffer *inBufPtr;    /* input buffer */
  915.     Proc_MigBuffer *outBufPtr;    /* output buffer (stays NIL) */
  916. {
  917.     ReturnStatus status = SUCCESS;
  918.     Address bufPtr;
  919.     register int i;
  920.     Proc_EncapInfo *infoPtr;
  921.  
  922.     Proc_Lock(procPtr);
  923.     procPtr->genFlags = (procPtr->genFlags | PROC_MIGRATING) &
  924.     ~PROC_MIGRATION_DONE;
  925.  
  926.     /*
  927.      * Go through the buffer to deencapsulate the process module-by-module.
  928.      */
  929.     bufPtr = inBufPtr->ptr;
  930.     for (i = 0; i < PROC_MIG_NUM_CALLBACKS; i++) {
  931.     infoPtr = (Proc_EncapInfo *) bufPtr;
  932.     if (infoPtr->token != encapCallbacks[i].token) {
  933.         /*
  934.          * This callback wasn't used.
  935.          */
  936.         continue;
  937.     }
  938.     if (infoPtr->special) {
  939.         /*
  940.          * This is where we'd like to handle special cases like shared
  941.          * memory processes.  For now, this should never happen.
  942.          */
  943.         if (proc_MigDebugLevel > 0) {
  944.         panic("ProcMigReceiveProcess: special flag set?! (continuable -- but call Fred)");
  945.         }
  946.         procPtr->genFlags &= ~PROC_MIGRATING;
  947.         Proc_Unlock(procPtr);
  948.         return(PROC_MIGRATION_REFUSED);
  949.     }
  950.     if (proc_MigDebugLevel > 5) {
  951.         printf("Calling deencapFunc %d\n", i);
  952.     }
  953.     bufPtr += sizeof(Proc_EncapInfo);
  954.     status = (*encapCallbacks[i].deencapFunc)(procPtr, infoPtr, bufPtr);
  955. #ifdef lint
  956.     status = DeencapProcState(procPtr, infoPtr, bufPtr);
  957.     status = ProcExecDeencapState(procPtr, infoPtr, bufPtr);
  958.     status = Vm_DeencapState(procPtr, infoPtr, bufPtr);
  959.     status = Fs_DeencapFileState(procPtr, infoPtr, bufPtr);
  960.     status = Mach_DeencapState(procPtr, infoPtr, bufPtr);
  961.     status = Prof_DeencapState(procPtr, infoPtr, bufPtr);
  962.     status = Sig_DeencapState(procPtr, infoPtr, bufPtr);
  963. #endif /* lint */
  964.     if (status != SUCCESS) {
  965.         printf("Warning: ProcMigReceiveProcess: error returned by deencapsulation procedure %s:\n\t%s.\n",
  966. #ifdef BREAKS_KDBX
  967.            callbackNames[i].deencapFunc,
  968. #else /* BREAKS_KDBX */
  969.            "(can't get name)", 
  970. #endif /* BREAKS_KDBX */
  971.            Stat_GetMsg(status));
  972.         procPtr->genFlags &= ~PROC_MIGRATING;
  973.         Proc_Unlock(procPtr);
  974.         return(status);
  975.     }
  976.     bufPtr += infoPtr->size;
  977.     }
  978.  
  979.     /*
  980.      * Update statistics.
  981.      */
  982.     if (procPtr->genFlags & PROC_FOREIGN) {
  983.     PROC_MIG_INC_STAT(foreign);
  984. #ifndef CLEAN
  985.     if (proc_MigDoStats) {
  986.         PROC_MIG_INC_STAT(imports);
  987.     }
  988. #endif /* CLEAN */
  989.     } else {
  990. #ifndef CLEAN
  991.     if (proc_MigDoStats) {
  992.         PROC_MIG_INC_STAT(returns);
  993.         PROC_MIG_DEC_STAT(remote);
  994.     }
  995. #endif /* CLEAN */
  996.     }
  997.  
  998.     procPtr->genFlags &= ~PROC_MIGRATING;
  999.     Proc_Unlock(procPtr);
  1000.  
  1001.     return(status);
  1002. }
  1003.  
  1004.  
  1005.  
  1006. /*
  1007.  * Define the process state that is sent during migration.
  1008.  * See proc.h for explanations of these fields.
  1009.  * This structure is followed by a variable-length string containing
  1010.  * procPtr->argString, padded to an integer boundary.
  1011.  */
  1012. typedef struct {
  1013.     int            migFlags;
  1014.     Proc_PID        parentID;
  1015.     int            familyID;
  1016.     int            userID;
  1017.     int            effectiveUserID;
  1018.     int            genFlags;
  1019.     int            syncFlags;
  1020.     int            schedFlags;
  1021.     int            exitFlags;
  1022.     int         billingRate;
  1023.     unsigned int     recentUsage;
  1024.     unsigned int     weightedUsage;
  1025.     unsigned int     unweightedUsage;
  1026.     Proc_Time        kernelCpuUsage;
  1027.     Proc_Time        userCpuUsage;
  1028.     Proc_Time        childKernelCpuUsage;
  1029.     Proc_Time        childUserCpuUsage;
  1030.     int         numQuantumEnds;
  1031.     int            numWaitEvents;
  1032.     unsigned int     schedQuantumTicks;
  1033.     Proc_TimerInterval  timers[PROC_MAX_TIMER + 1];
  1034.     int            argStringLength;
  1035.     int            unixProgress;
  1036. } EncapState;
  1037.  
  1038. #define COPY_STATE(from, to, field) to->field = from->field
  1039.  
  1040. /*
  1041.  * A process is allowed to update its userID, effectiveUserID,
  1042.  * billingRate, or familyID.  If any of these fields is modified, all
  1043.  * of them are transferred to the remote host.
  1044.  */
  1045.  
  1046. typedef struct {
  1047.     int            familyID;
  1048.     int            userID;
  1049.     int            effectiveUserID;
  1050.     int         billingRate;
  1051. } UpdateEncapState;
  1052.  
  1053. /*
  1054.  * Parameters for a remote Proc_Suspend or resume.
  1055.  */
  1056.  
  1057. typedef struct {
  1058.     int        termReason; /* Reason why process went to this state.*/
  1059.     int        termStatus; /* Termination status.*/
  1060.     int        termCode;   /* Termination code. */
  1061.     int        flags;        /* Exit flags. */
  1062. } SuspendInfo;
  1063.  
  1064. /*
  1065.  * Extra info used for suspend callback.
  1066.  */
  1067.  
  1068. typedef struct {
  1069.     Proc_PID    processID;    /* Process being suspended/resumed. */
  1070.     SuspendInfo info;        /* Info to pass to home machine. */
  1071. } SuspendCallbackInfo;
  1072.  
  1073. /*
  1074.  *----------------------------------------------------------------------
  1075.  *
  1076.  * GetProcEncapSize --
  1077.  *
  1078.  *    Determine the size of the encapsulated process state.
  1079.  *
  1080.  * Results:
  1081.  *    SUCCESS is returned directly; the size of the encapsulated state
  1082.  *    is returned in infoPtr->size.
  1083.  *
  1084.  * Side effects:
  1085.  *    None.
  1086.  *
  1087.  *----------------------------------------------------------------------
  1088.  */
  1089.  
  1090. /* ARGSUSED */
  1091. static ReturnStatus
  1092. GetProcEncapSize(procPtr, hostID, infoPtr)
  1093.     Proc_ControlBlock *procPtr;            /* process being migrated */
  1094.     int hostID;                    /* host to which it migrates */
  1095.     Proc_EncapInfo *infoPtr;            /* area w/ information about
  1096.                          * encapsulated state */
  1097. {
  1098.     infoPtr->size = sizeof(EncapState) +
  1099.     Byte_AlignAddr(strlen(procPtr->argString) + 1);
  1100.     /*
  1101.      * The clientData part of the EncapInfo struct is used to indicate
  1102.      * that the process is migrating home.
  1103.      */
  1104.     if (procPtr->genFlags & PROC_FOREIGN) {
  1105.     infoPtr->data = (ClientData) 1;
  1106.     if (proc_MigDebugLevel > 4) {
  1107.         printf("Encapsulating foreign process %x.\n", procPtr->processID);
  1108.     }
  1109.     } else {
  1110.     infoPtr->data = (ClientData) 0;
  1111.     if (proc_MigDebugLevel > 4) {
  1112.         printf("Encapsulating local process %x.\n", procPtr->processID);
  1113.     }
  1114.     }
  1115.  
  1116.     return(SUCCESS);    
  1117. }
  1118.  
  1119.  
  1120. /*
  1121.  *----------------------------------------------------------------------
  1122.  *
  1123.  * EncapProcState --
  1124.  *
  1125.  *    Encapsulate the state of a process from the Proc_ControlBlock
  1126.  *    and return it in the buffer provided.
  1127.  *
  1128.  * Results:
  1129.  *    SUCCESS.  The buffer is filled.
  1130.  *
  1131.  * Side effects:
  1132.  *    None.
  1133.  *----------------------------------------------------------------------
  1134.  */
  1135.  
  1136. /* ARGSUSED */
  1137. static ReturnStatus
  1138. EncapProcState(procPtr, hostID, infoPtr, bufPtr)
  1139.     register Proc_ControlBlock     *procPtr; /* The process being migrated */
  1140.     int hostID;                  /* host to which it migrates */
  1141.     Proc_EncapInfo *infoPtr;
  1142.     Address bufPtr;
  1143. {
  1144.     int argStringLength;
  1145.     EncapState *encapPtr = (EncapState *) bufPtr;
  1146.     int i;
  1147.     ReturnStatus status;
  1148.     Proc_TimerInterval timer;
  1149.  
  1150.     COPY_STATE(procPtr, encapPtr, migFlags);
  1151.     COPY_STATE(procPtr, encapPtr, parentID);
  1152.     COPY_STATE(procPtr, encapPtr, familyID);
  1153.     COPY_STATE(procPtr, encapPtr, userID);
  1154.     COPY_STATE(procPtr, encapPtr, effectiveUserID);
  1155.     COPY_STATE(procPtr, encapPtr, genFlags);
  1156.     COPY_STATE(procPtr, encapPtr, syncFlags);
  1157.     COPY_STATE(procPtr, encapPtr, schedFlags);
  1158.     COPY_STATE(procPtr, encapPtr, exitFlags);
  1159.     COPY_STATE(procPtr, encapPtr, billingRate);
  1160.     COPY_STATE(procPtr, encapPtr, recentUsage);
  1161.     COPY_STATE(procPtr, encapPtr, weightedUsage);
  1162.     COPY_STATE(procPtr, encapPtr, unweightedUsage);
  1163.     COPY_STATE(procPtr, encapPtr, kernelCpuUsage);
  1164.     COPY_STATE(procPtr, encapPtr, userCpuUsage);
  1165.     COPY_STATE(procPtr, encapPtr, childKernelCpuUsage);
  1166.     COPY_STATE(procPtr, encapPtr, childUserCpuUsage);
  1167.     COPY_STATE(procPtr, encapPtr, numQuantumEnds);
  1168.     COPY_STATE(procPtr, encapPtr, numWaitEvents);
  1169.     COPY_STATE(procPtr, encapPtr, schedQuantumTicks);
  1170.     COPY_STATE(procPtr, encapPtr, unixProgress);
  1171.  
  1172.  
  1173.     /*
  1174.      * Get the timer state in an easy-to-transfer form.  Unlock
  1175.      * the process first since ProcChangeTimer will lock it.
  1176.      */
  1177.     timer.interval = time_ZeroSeconds;
  1178.     timer.curValue = time_ZeroSeconds;
  1179.     
  1180.     Proc_Unlock(procPtr);
  1181.     for (i = 0; i <= PROC_MAX_TIMER; i++) {
  1182.     status = ProcChangeTimer(i, &timer, &encapPtr->timers[i], FALSE);
  1183. #define DEBUG_TIMER
  1184. #ifdef DEBUG_TIMER
  1185.     if ((encapPtr->timers[i].curValue.seconds < 0) || 
  1186.         (encapPtr->timers[i].curValue.microseconds < 0) ||
  1187.         (encapPtr->timers[i].curValue.microseconds > ONE_SECOND) ||
  1188.         (encapPtr->timers[i].interval.seconds < 0) || 
  1189.         (encapPtr->timers[i].interval.microseconds < 0) ||
  1190.         (encapPtr->timers[i].interval.microseconds > ONE_SECOND)) {
  1191.         panic("Migration error: timer value (<%d,%d>@<%d,%d>)  is bad.\n",
  1192.           encapPtr->timers[i].curValue.seconds,
  1193.           encapPtr->timers[i].curValue.microseconds,
  1194.           encapPtr->timers[i].interval.seconds,
  1195.           encapPtr->timers[i].interval.microseconds);
  1196.         Proc_Lock(procPtr);
  1197.         return(FAILURE);
  1198.     }
  1199. #endif /* DEBUG_TIMER */
  1200.  
  1201.     if (status != SUCCESS) {
  1202.         if (proc_MigDebugLevel > 0) {
  1203.         printf("EncapProcState: error returned from ProcChangeTimer: %s.\n",
  1204.                Stat_GetMsg(status));
  1205.         }
  1206.         Proc_Lock(procPtr);
  1207.         return(status);
  1208.     }
  1209.     }
  1210.     Proc_Lock(procPtr);
  1211.  
  1212.     bufPtr += sizeof(EncapState);
  1213.     argStringLength = Byte_AlignAddr(strlen(procPtr->argString) + 1);
  1214.     encapPtr->argStringLength = argStringLength;
  1215.     (void) strncpy(bufPtr, procPtr->argString, argStringLength);
  1216.  
  1217.  
  1218.     /*
  1219.      * If we're migrating away from home, subtract the process's current
  1220.      * CPU usage so it can be added in again when the process returns
  1221.      * here.  Passing negative tick values seems like a relatively easy
  1222.      * way to subtract time, though perhaps we should pass a separate parameter
  1223.      * to ProcRecordUsage instead and call Timer_AddTicks or
  1224.      * Timer_SubtractTicks depending on the parameter.
  1225.      */
  1226. #ifndef CLEAN
  1227.     if (infoPtr->data == 0) {
  1228.     Timer_Ticks ticks;
  1229.     Timer_SubtractTicks(timer_TicksZeroSeconds,
  1230.                 procPtr->kernelCpuUsage.ticks,
  1231.                 &ticks);
  1232.     Timer_SubtractTicks(ticks, procPtr->userCpuUsage.ticks,
  1233.                 &ticks);
  1234.     ProcRecordUsage(ticks, PROC_MIG_USAGE_REMOTE_CPU);
  1235.     }
  1236. #endif /* CLEAN */
  1237.     return(SUCCESS);
  1238. }
  1239.  
  1240.  
  1241. /*
  1242.  *----------------------------------------------------------------------
  1243.  *
  1244.  * DeencapProcState --
  1245.  *
  1246.  *    Get information from a Proc_ControlBlock from another host.
  1247.  *    The information is contained in the parameter ``buffer''.
  1248.  *    The process control block should be locked on entry and exit.
  1249.  *
  1250.  * Results:
  1251.  *    Usually SUCCESS.  Can propagate an error return from 
  1252.  *    ProcChangeTimer.  Returns PROC_MIGRATION_REFUSED if the 
  1253.  *    process has been flagged as unmigratable and this is not its
  1254.  *    home node.
  1255.  *
  1256.  * Side effects:
  1257.  *    None.
  1258.  *----------------------------------------------------------------------
  1259.  */
  1260.  
  1261. /* ARGSUSED */
  1262. static ReturnStatus
  1263. DeencapProcState(procPtr, infoPtr, bufPtr)
  1264.     register Proc_ControlBlock     *procPtr; /* The process being migrated */
  1265.     Proc_EncapInfo *infoPtr;          /* information about the buffer */
  1266.     Address bufPtr;              /* buffer containing data */
  1267. {
  1268.     Boolean         home;
  1269.     EncapState *encapPtr = (EncapState *) bufPtr;
  1270.     int i;
  1271.     ReturnStatus status;
  1272.     Timer_Ticks ticks;
  1273.     
  1274.     if (infoPtr->data == 0) {
  1275.     if (proc_MigDebugLevel > 4) {
  1276.         printf("Deencapsulating foreign process %x.\n", procPtr->processID);
  1277.     }
  1278.     home = FALSE;
  1279.     } else {
  1280.     if (proc_MigDebugLevel > 4) {
  1281.         printf("Deencapsulating local process %x.\n", procPtr->processID);
  1282.     }
  1283.     home = TRUE;
  1284.     }
  1285.  
  1286.  
  1287.     COPY_STATE(encapPtr, procPtr, migFlags);
  1288.     COPY_STATE(encapPtr, procPtr, parentID);
  1289.     COPY_STATE(encapPtr, procPtr, familyID);
  1290.     COPY_STATE(encapPtr, procPtr, userID);
  1291.     COPY_STATE(encapPtr, procPtr, effectiveUserID);
  1292.     COPY_STATE(encapPtr, procPtr, genFlags);
  1293.     COPY_STATE(encapPtr, procPtr, syncFlags);
  1294.     COPY_STATE(encapPtr, procPtr, schedFlags);
  1295.     COPY_STATE(encapPtr, procPtr, exitFlags);
  1296.     COPY_STATE(encapPtr, procPtr, billingRate);
  1297.     COPY_STATE(encapPtr, procPtr, recentUsage);
  1298.     COPY_STATE(encapPtr, procPtr, weightedUsage);
  1299.     COPY_STATE(encapPtr, procPtr, unweightedUsage);
  1300.     COPY_STATE(encapPtr, procPtr, kernelCpuUsage);
  1301.     COPY_STATE(encapPtr, procPtr, userCpuUsage);
  1302.     COPY_STATE(encapPtr, procPtr, childKernelCpuUsage);
  1303.     COPY_STATE(encapPtr, procPtr, childUserCpuUsage);
  1304.     COPY_STATE(encapPtr, procPtr, numQuantumEnds);
  1305.     COPY_STATE(encapPtr, procPtr, numWaitEvents);
  1306.     COPY_STATE(encapPtr, procPtr, schedQuantumTicks);
  1307.     COPY_STATE(encapPtr, procPtr, unixProgress);
  1308.  
  1309.     /* 
  1310.      * The process should never be flagged as unmigratable, so 
  1311.      * complain if it is.  Allow "unmigratable" processes to migrate 
  1312.      * back to the home node, but don't let them go anywhere else.
  1313.      */
  1314.     if (procPtr->genFlags & PROC_DONT_MIGRATE) {
  1315.     Sys_HostPrint(procPtr->peerHostID,
  1316.               "wants to give us an unmigratable process.\n");
  1317.     if (!home) {
  1318.         return PROC_MIGRATION_REFUSED;
  1319.     }
  1320.     }
  1321.  
  1322.     /*
  1323.      * Set the effective process for this processor while doing the
  1324.      * ProcChangeTimer since we're doing it on behalf of another
  1325.      * process.
  1326.      */
  1327.  
  1328.     Proc_SetEffectiveProc(procPtr);
  1329.  
  1330.     Proc_Unlock(procPtr);
  1331.     for (i = 0; i <= PROC_MAX_TIMER; i++) {
  1332.     status = ProcChangeTimer(i, &encapPtr->timers[i],
  1333.                  (Proc_TimerInterval *) USER_NIL, FALSE);
  1334.     if (status != SUCCESS) {
  1335.         if (proc_MigDebugLevel > 0) {
  1336.         printf("DeencapProcState: error returned from ProcChangeTimer: %s.\n",
  1337.                Stat_GetMsg(status));
  1338.         }
  1339.         Proc_Lock(procPtr);
  1340.         return(status);
  1341.     }
  1342.     }
  1343.     Proc_Lock(procPtr);
  1344.  
  1345.     Proc_SetEffectiveProc((Proc_ControlBlock *) NIL);
  1346.  
  1347.     bufPtr += sizeof(*encapPtr);
  1348.     if (procPtr->argString != (char *) NIL) {
  1349.     free(procPtr->argString);
  1350.     }
  1351.     procPtr->argString = (char *) malloc(encapPtr->argStringLength);
  1352.     bcopy(bufPtr, (Address) procPtr->argString, encapPtr->argStringLength);
  1353.  
  1354.     procPtr->genFlags |= PROC_NO_VM;
  1355.     if (home) {
  1356.     procPtr->genFlags &= (~PROC_FOREIGN);
  1357.     procPtr->kcallTable = mach_NormalHandlers;
  1358.     } else {
  1359.     procPtr->genFlags |= PROC_FOREIGN;
  1360.     procPtr->kcallTable = mach_MigratedHandlers;
  1361.     }
  1362.     procPtr->genFlags &= ~PROC_MIG_PENDING;
  1363.     procPtr->schedFlags &=
  1364.     ~(SCHED_STACK_IN_USE | SCHED_CONTEXT_SWITCH_PENDING);
  1365.  
  1366.     /*
  1367.      * Initialize some of the fields as if for a new process.  If migrating
  1368.      * home, these are already set up.   Fix up dependencies.
  1369.      */
  1370.     procPtr->state         = PROC_NEW;
  1371.     Vm_ProcInit(procPtr);
  1372.     procPtr->event            = NIL;
  1373.  
  1374.     if (!home) {
  1375.     /*
  1376.      *  Initialize our child list to remove any old links.
  1377.      */
  1378.     List_Init((List_Links *) procPtr->childList);
  1379.  
  1380.     } else {
  1381.     /*
  1382.      * Forget the dependency on the other host; we're running
  1383.      * locally now.
  1384.      */
  1385.     ProcMigRemoveDependency(procPtr->processID, TRUE);
  1386.     /*
  1387.      * Update remote CPU usage stats.
  1388.      */
  1389. #ifndef CLEAN
  1390.     Timer_AddTicks(procPtr->kernelCpuUsage.ticks,
  1391.             procPtr->userCpuUsage.ticks, &ticks);
  1392.     ProcRecordUsage(ticks, PROC_MIG_USAGE_REMOTE_CPU);
  1393. #endif /* CLEAN */
  1394.     if (procPtr->migFlags & PROC_EVICTING) {
  1395.         procPtr->migFlags &= ~PROC_EVICTING;
  1396. #ifndef CLEAN
  1397.         if (!(procPtr->migFlags & PROC_WAS_EVICTED)) {
  1398.         procPtr->migFlags |= PROC_WAS_EVICTED;
  1399.         procPtr->preEvictionUsage.ticks = ticks;
  1400.         }
  1401. #endif /* CLEAN */
  1402.     } else if (!home) {
  1403.         procPtr->migFlags &= ~PROC_WAS_EVICTED;
  1404.     }
  1405.     }
  1406.  
  1407.  
  1408.     if (proc_MigDebugLevel > 4) {
  1409.     printf("Received process state for process %x.\n", procPtr->processID);
  1410.     }
  1411.  
  1412.     return(SUCCESS);
  1413. }
  1414.  
  1415.  
  1416. /*
  1417.  *----------------------------------------------------------------------
  1418.  *
  1419.  * Proc_MigUpdateInfo --
  1420.  *
  1421.  *    Send the updateable portions of the state of a process to the
  1422.  *    host on which it is currently executing.  This requires
  1423.  *    packaging the relevant information from the Proc_ControlBlock
  1424.  *    and sending it via an RPC.
  1425.  *
  1426.  *     The process is assumed to be locked.
  1427.  *
  1428.  * Results:
  1429.  *    A ReturnStatus is returned to indicate the status of the RPC.
  1430.  *
  1431.  * Side effects:
  1432.  *    A remote procedure call is performed and the process state
  1433.  *    is transferred.
  1434.  *
  1435.  *----------------------------------------------------------------------
  1436.  */
  1437.  
  1438. ReturnStatus
  1439. Proc_MigUpdateInfo(procPtr)
  1440.     Proc_ControlBlock     *procPtr; /* The migrated process */
  1441. {
  1442.     ReturnStatus status;
  1443.     ProcMigCmd cmd;
  1444.     UpdateEncapState state;
  1445.     UpdateEncapState *statePtr = &state;
  1446.     Proc_MigBuffer inBuf;
  1447.  
  1448.     COPY_STATE(procPtr, statePtr, familyID);
  1449.     COPY_STATE(procPtr, statePtr, userID);
  1450.     COPY_STATE(procPtr, statePtr, effectiveUserID);
  1451.     COPY_STATE(procPtr, statePtr, billingRate);
  1452.  
  1453.     /*
  1454.      * Set up for the RPC.
  1455.      */
  1456.     cmd.command = PROC_MIGRATE_CMD_UPDATE;
  1457.     cmd.remotePid = procPtr->peerProcessID;
  1458.     inBuf.size = sizeof(UpdateEncapState);
  1459.     inBuf.ptr = (Address) statePtr;
  1460.  
  1461.     status = ProcMigCommand(procPtr->peerHostID, &cmd, &inBuf,
  1462.                 (Proc_MigBuffer *) NIL);
  1463.  
  1464.     if (status != SUCCESS && proc_MigDebugLevel > 0) {
  1465.     printf("Warning: Proc_MigUpdateInfo: error returned updating information on host %d:\n\t%s.\n",
  1466.         procPtr->peerHostID,Stat_GetMsg(status));
  1467.     }
  1468.     return(status);
  1469. }
  1470.  
  1471.  
  1472. /*
  1473.  *----------------------------------------------------------------------
  1474.  *
  1475.  * ProcMigGetUpdate --
  1476.  *
  1477.  *    Receive the updateable portions of the state of a process from its
  1478.  *    home node.
  1479.  *
  1480.  * Results:
  1481.  *    SUCCESS.
  1482.  *
  1483.  * Side effects:
  1484.  *    The process's control block is locked and then updated.
  1485.  *
  1486.  *----------------------------------------------------------------------
  1487.  */
  1488.  
  1489. /* ARGSUSED */
  1490. ReturnStatus
  1491. ProcMigGetUpdate(cmdPtr, procPtr, inBufPtr, outBufPtr)
  1492.     ProcMigCmd *cmdPtr;/* contains ID of process on this host */
  1493.     Proc_ControlBlock *procPtr; /* ptr to process control block */
  1494.     Proc_MigBuffer *inBufPtr;    /* input buffer */
  1495.     Proc_MigBuffer *outBufPtr;    /* output buffer (stays NIL) */
  1496. {
  1497.     UpdateEncapState *statePtr = (UpdateEncapState *) inBufPtr->ptr;
  1498.  
  1499.     Proc_Lock(procPtr);
  1500.     COPY_STATE(statePtr, procPtr, familyID);
  1501.     COPY_STATE(statePtr, procPtr, userID);
  1502.     COPY_STATE(statePtr, procPtr, effectiveUserID);
  1503.     COPY_STATE(statePtr, procPtr, billingRate);
  1504.     Proc_Unlock(procPtr);
  1505.     return(SUCCESS);
  1506.  
  1507. }
  1508.  
  1509.  
  1510. /*
  1511.  *----------------------------------------------------------------------
  1512.  *
  1513.  * ProcRemoteSuspend --
  1514.  *
  1515.  *    Tell the home node of a process that it has been suspended or resumed.
  1516.  *    This routine is called from within the signal handling routines.
  1517.  *
  1518.  * Results:
  1519.  *    None.
  1520.  *
  1521.  * Side effects:
  1522.  *    Sets up a background process to make an RPC.
  1523.  *
  1524.  *----------------------------------------------------------------------
  1525.  */
  1526.  
  1527. void
  1528. ProcRemoteSuspend(procPtr, exitFlags)
  1529.     register Proc_ControlBlock     *procPtr;  /* Process whose state is changing. */
  1530.     int exitFlags;               /* Flags to set for child. */
  1531. {
  1532.     ReturnStatus status;
  1533.     SuspendCallbackInfo *callPtr;         /* Information for the callback. */
  1534.     SuspendInfo *infoPtr;         /* Info to pass back. */
  1535.  
  1536.     if (proc_MigDebugLevel > 4) {
  1537.     printf("ProcRemoteSuspend(%x) called.\n", procPtr->processID);
  1538.     }
  1539.  
  1540.     status = Recov_IsHostDown(procPtr->peerHostID);
  1541.     if (status != SUCCESS) {
  1542.     if (proc_MigDebugLevel > 0) {
  1543.         printf("ProcRemoteSuspend: host %d is down; killing process %x.\n",
  1544.                procPtr->peerHostID, procPtr->processID);
  1545.     }
  1546.     /*
  1547.      * Perform an exit on behalf of the process -- it's not
  1548.      * in a state where we can signal it.  The process is
  1549.          * unlocked as a side effect.
  1550.      */
  1551.     ProcExitProcess(procPtr, PROC_TERM_DESTROYED, (int) PROC_NO_PEER, 0,
  1552.             FALSE);
  1553.     /*
  1554.      * This point should not be reached, but the N-O-T-R-E-A-C-H-E-D
  1555.      * directive causes a complaint when there's code after it.
  1556.      */
  1557.     panic("ProcRemoteSuspend: Proc_ExitInt returned.\n");
  1558.     return;
  1559.     }
  1560.  
  1561.     callPtr = (SuspendCallbackInfo *) malloc(sizeof(SuspendCallbackInfo));
  1562.     infoPtr = &callPtr->info;
  1563.     callPtr->processID = procPtr->processID;
  1564.  
  1565.     COPY_STATE(procPtr, infoPtr, termReason);
  1566.     COPY_STATE(procPtr, infoPtr, termStatus);
  1567.     COPY_STATE(procPtr, infoPtr, termCode);
  1568.     infoPtr->flags = exitFlags;
  1569.     Proc_CallFunc(SuspendCallback, (ClientData) callPtr, 0);
  1570.     
  1571. }
  1572.  
  1573.  
  1574. /*
  1575.  *----------------------------------------------------------------------
  1576.  *
  1577.  * SuspendCallback --
  1578.  *
  1579.  *    Tell the home node of a process that it has been suspended or resumed.
  1580.  *    This is called via a Proc_CallFunc so the signal monitor lock
  1581.  *    is not held.
  1582.  *
  1583.  * Results:
  1584.  *    None.
  1585.  *
  1586.  * Side effects:
  1587.  *    A remote procedure call is performed.
  1588.  *
  1589.  *----------------------------------------------------------------------
  1590.  */
  1591.  
  1592. /* ARGSUSED */
  1593. static void
  1594. SuspendCallback(data, callInfoPtr)
  1595.     ClientData        data;
  1596.     Proc_CallInfo    *callInfoPtr;        /* not used */
  1597. {
  1598.     SuspendCallbackInfo *callPtr;    /* Pointer to callback info. */
  1599.     register Proc_ControlBlock     *procPtr;  /* Process whose state is changing. */
  1600.     ReturnStatus status;
  1601.     int numTries;            /* number of times trying RPC */
  1602.     ProcMigCmd cmd;
  1603.     Proc_MigBuffer inBuf;
  1604.     int host = 0;
  1605.  
  1606.     callPtr = (SuspendCallbackInfo *) data;
  1607.     if (proc_MigDebugLevel > 4) {
  1608.     printf("SuspendCallback(%x) called.\n", callPtr->processID);
  1609.     }
  1610.     procPtr = Proc_LockPID(callPtr->processID);
  1611.     if (procPtr == (Proc_ControlBlock *) NIL) {
  1612.     if (proc_MigDebugLevel > 1) {
  1613.         printf("SuspendCallback: no such process (%x).\n",
  1614.            callPtr->processID);
  1615.     }
  1616.     status = PROC_NO_PEER;
  1617.     goto done;
  1618.     }
  1619.     host = procPtr->peerHostID;
  1620.     cmd.remotePid = procPtr->peerProcessID;
  1621.  
  1622.     /*
  1623.      * Now that we have the relevant info, unlock the process while we're
  1624.      * doing the RPC.  We don't need it anymore anyway.
  1625.      */
  1626.  
  1627.     Proc_Unlock(procPtr);
  1628.  
  1629.     /*
  1630.      * Set up for the RPC.
  1631.      */
  1632.     cmd.command = PROC_MIGRATE_CMD_SUSPEND;
  1633.  
  1634.     inBuf.size = sizeof(SuspendInfo);
  1635.     inBuf.ptr = (Address) &callPtr->info;
  1636.  
  1637.     for (numTries = 0; numTries < PROC_MAX_RPC_RETRIES; numTries++) {
  1638.     status = ProcMigCommand(host, &cmd, &inBuf,
  1639.                 (Proc_MigBuffer *) NIL);
  1640.     if (status != RPC_TIMEOUT) {
  1641.         break;
  1642.     }
  1643.     status = Proc_WaitForHost(host);
  1644.     if (status != SUCCESS) {
  1645.         break;
  1646.     }
  1647.     }
  1648.     done:
  1649.     if (status != SUCCESS && proc_MigDebugLevel > 2) {
  1650.     printf("Warning: SuspendCallback: error returned passing suspend to host %d:\n\t%s.\n",
  1651.         host,Stat_GetMsg(status));
  1652.     } else if (proc_MigDebugLevel > 4) {
  1653.     printf("SuspendCallback(%x) completed successfully.\n",
  1654.            callPtr->processID);
  1655.     }
  1656.     free ((Address) callPtr);
  1657. }
  1658.  
  1659.  
  1660. /*
  1661.  *----------------------------------------------------------------------
  1662.  *
  1663.  * ProcMigGetSuspend --
  1664.  *
  1665.  *    Receive the new exit status of a process from its remote node.
  1666.  *
  1667.  * Results:
  1668.  *    SUCCESS.
  1669.  *
  1670.  * Side effects:
  1671.  *    The process's control block is locked and then updated.
  1672.  *
  1673.  *----------------------------------------------------------------------
  1674.  */
  1675.  
  1676. /* ARGSUSED */
  1677. ReturnStatus
  1678. ProcMigGetSuspend(cmdPtr, procPtr, inBufPtr, outBufPtr)
  1679.     ProcMigCmd *cmdPtr;/* contains ID of process on this host */
  1680.     Proc_ControlBlock *procPtr; /* ptr to process control block */
  1681.     Proc_MigBuffer *inBufPtr;    /* input buffer */
  1682.     Proc_MigBuffer *outBufPtr;    /* output buffer (stays NIL) */
  1683. {
  1684.     register SuspendInfo *infoPtr = (SuspendInfo *) inBufPtr->ptr;
  1685.  
  1686.     Proc_Lock(procPtr);
  1687.  
  1688.     COPY_STATE(infoPtr, procPtr, termReason);
  1689.     COPY_STATE(infoPtr, procPtr, termStatus);
  1690.     COPY_STATE(infoPtr, procPtr, termCode);
  1691.  
  1692.     Proc_InformParent(procPtr, infoPtr->flags);
  1693.     Proc_Unlock(procPtr);
  1694.     return(SUCCESS);
  1695.  
  1696. }
  1697.  
  1698.  
  1699. /*
  1700.  *----------------------------------------------------------------------
  1701.  *
  1702.  * ProcMigEncapCallback --
  1703.  *
  1704.  *    Handle a callback on behalf of a module requesting more data.
  1705.  *    Not yet implemented.
  1706.  *
  1707.  * Results:
  1708.  *    A ReturnStatus, dependent on the module doing the callback.
  1709.  *
  1710.  * Side effects:
  1711.  *    Variable.
  1712.  *
  1713.  *----------------------------------------------------------------------
  1714.  */
  1715.  
  1716. /* ARGSUSED */
  1717. ReturnStatus
  1718. ProcMigEncapCallback(cmdPtr, procPtr, inBufPtr, outBufPtr)
  1719.     ProcMigCmd *cmdPtr;/* contains ID of process on this host */
  1720.     Proc_ControlBlock *procPtr; /* ptr to process control block */
  1721.     Proc_MigBuffer *inBufPtr;    /* input buffer */
  1722.     Proc_MigBuffer *outBufPtr;    /* output buffer (stays NIL) */
  1723. {
  1724.     return(FAILURE);
  1725. }
  1726.  
  1727.  
  1728. /*
  1729.  *----------------------------------------------------------------------
  1730.  *
  1731.  * ProcMigKillRemoteCopy --
  1732.  *
  1733.  *    Inform the remote host that a failure occurred during migration,
  1734.  *     so the incomplete process on the remote host will kill the process.
  1735.  *    This just sets up and issues a MigCommand.
  1736.  *
  1737.  * Results:
  1738.  *    None.  The caller doesn't normally care about the status of the
  1739.  *    RPC.
  1740.  *
  1741.  * Side effects:
  1742.  *    A remote procedure call is performed and the migrated process
  1743.  *    is killed.
  1744.  *
  1745.  *----------------------------------------------------------------------
  1746.  */
  1747.  
  1748. /* ARGSUSED */
  1749. void
  1750. ProcMigKillRemoteCopy(data, infoPtr)
  1751.     ClientData        data;        /* The ID of the remote process */
  1752.     Proc_CallInfo    *infoPtr;    /* unused. */
  1753. {
  1754.     Proc_PID processID = (Proc_PID) data;
  1755.     ReturnStatus status;
  1756.     ProcMigCmd cmd;
  1757.     int hostID;                     /* Host to notify. */
  1758.  
  1759.     /*
  1760.      * Set up for the RPC.
  1761.      */
  1762.     cmd.command = PROC_MIGRATE_CMD_DESTROY;
  1763.     cmd.remotePid = processID;
  1764.     hostID = Proc_GetHostID(processID);
  1765.  
  1766.     status = ProcMigCommand(hostID, &cmd, (Proc_MigBuffer *) NIL,
  1767.                 (Proc_MigBuffer *) NIL);
  1768.  
  1769.     if (status != SUCCESS && proc_MigDebugLevel > 2) {
  1770.     printf("Warning: KillRemoteCopy: error returned by Rpc_Call: %s.\n",
  1771.         Stat_GetMsg(status));
  1772.     }
  1773. }
  1774.  
  1775.  
  1776.  
  1777. /*
  1778.  *----------------------------------------------------------------------
  1779.  *
  1780.  * Proc_FlagMigration --
  1781.  *
  1782.  *    Mark a process as waiting to migrate.  This will cause the process
  1783.  *    to trap to the Proc_MigrateTrap routine after the next time it
  1784.  *    traps into the kernel. 
  1785.  *
  1786.  *    The calling routine is assumed to hold the lock for the process.
  1787.  *
  1788.  * Results:
  1789.  *    None.
  1790.  *
  1791.  * Side effects:
  1792.  *    The process is flagged for migration.  If the process is suspended,
  1793.  *    it is resumed.
  1794.  *
  1795.  *----------------------------------------------------------------------
  1796.  */
  1797.  
  1798. void
  1799. Proc_FlagMigration(procPtr, hostID, exec)
  1800.     Proc_ControlBlock     *procPtr;    /* The process being migrated */
  1801.     int hostID;                /* Host to which it migrates */
  1802.     Boolean exec;            /* Whether it's doing a remote exec */
  1803. {
  1804.  
  1805.     procPtr->genFlags |= PROC_MIG_PENDING;
  1806.     procPtr->genFlags &= ~PROC_MIGRATION_DONE;
  1807.     if (exec) {
  1808.     /*
  1809.      * We flag the process specially so we know to copy over exec
  1810.      * arguments.  
  1811.      */
  1812.     procPtr->genFlags |= PROC_REMOTE_EXEC_PENDING;
  1813.     }
  1814.     procPtr->peerHostID = hostID;
  1815.     if (procPtr->state == PROC_SUSPENDED) {
  1816.     Sig_SendProc(procPtr, SIG_RESUME, 0, (Address)0);
  1817.     }
  1818.     Sig_SendProc(procPtr, SIG_MIGRATE_TRAP, 0, (Address)0);
  1819.     Sig_AllowMigration(procPtr);
  1820.  
  1821. }
  1822.  
  1823.  
  1824. /*
  1825.  *----------------------------------------------------------------------
  1826.  *
  1827.  * ProcInitiateMigration --
  1828.  *    
  1829.  *    Send a message to a specific workstation requesting permission to
  1830.  *    migrate a process.
  1831.  *
  1832.  * Results:
  1833.  *    SUCCESS is returned if permission is granted.
  1834.  *    PROC_MIGRATION_REFUSED is returned if the host is not accepting
  1835.  *        migrated processes or it is not at the right migration
  1836.  *        level.
  1837.  *    GEN_INVALID_ID if the user doesn't have permission to migrate
  1838.  *        from this host or to the other host.
  1839.  *    Other errors may be returned by the rpc module.
  1840.  *
  1841.  * Side effects:
  1842.  *    A message is sent to the remote workstation.
  1843.  *
  1844.  *----------------------------------------------------------------------
  1845.  */
  1846.  
  1847. ReturnStatus
  1848. ProcInitiateMigration(procPtr, hostID)
  1849.     register Proc_ControlBlock *procPtr;        /* process to migrate */
  1850.     int hostID;                          /* host to which to migrate */
  1851. {
  1852.     ReturnStatus status;
  1853.     ProcMigInitiateCmd init;
  1854.     ProcMigCmd cmd;
  1855.     Proc_MigBuffer inBuf;
  1856.     Proc_MigBuffer outBuf;
  1857.     Proc_PID pid;
  1858.     int foreign;
  1859.     
  1860.  
  1861.     init.processID = procPtr->processID;
  1862.     init.version = proc_MigrationVersion;
  1863.     init.userID = procPtr->userID;
  1864.     init.clientID = rpc_SpriteID;
  1865.     if (procPtr->genFlags & PROC_FOREIGN) {
  1866.     foreign = 1;
  1867.     cmd.remotePid = procPtr->peerProcessID;
  1868.     } else {
  1869.     foreign = 0;
  1870.     cmd.remotePid = (Proc_PID) NIL;
  1871.     }
  1872.     cmd.command = PROC_MIGRATE_CMD_INIT;
  1873.     
  1874.     inBuf.ptr = (Address) &init;
  1875.     inBuf.size = sizeof(ProcMigInitiateCmd);
  1876.  
  1877.     outBuf.ptr = (Address) &pid;
  1878.     outBuf.size = sizeof(Proc_PID);
  1879.  
  1880.     status = ProcMigCommand(hostID, &cmd, &inBuf, &outBuf);
  1881.  
  1882.     if (status != SUCCESS) {
  1883.     if (proc_MigDebugLevel > 2) {
  1884.         printf(
  1885.            "%s ProcInitiateMigration: Error returned by host %d:\n\t%s\n",
  1886.            "Warning:", hostID, Stat_GetMsg(status));
  1887.     }
  1888.     } else if (!foreign) {
  1889.     procPtr->peerProcessID = pid;
  1890.     }
  1891.     return(status);
  1892. }
  1893.  
  1894.  
  1895.  
  1896. /*
  1897.  *----------------------------------------------------------------------
  1898.  *
  1899.  * ProcMigCommand --
  1900.  *
  1901.  *    Send a process migration-related command to another host.
  1902.  *    This sets up and performs the RPC itself.
  1903.  *
  1904.  * RPC: Input parameters:
  1905.  *        process ID
  1906.  *        command to perform
  1907.  *        data buffer
  1908.  *    Return parameters:
  1909.  *        ReturnStatus
  1910.  *        data buffer
  1911.  *
  1912.  * Results:
  1913.  *    A ReturnStatus is returned to indicate the status of the RPC.
  1914.  *    The data buffer is filled by the RPC if a result is returned by
  1915.  *    the other host.
  1916.  *
  1917.  * Side effects:
  1918.  *    None.
  1919.  *
  1920.  *----------------------------------------------------------------------
  1921.  */
  1922.  
  1923. ReturnStatus
  1924. ProcMigCommand(host, cmdPtr, inPtr, outPtr)
  1925.     int host;             /* host to send command to */
  1926.     ProcMigCmd *cmdPtr; /* command to send */
  1927.     Proc_MigBuffer *inPtr;     /* pair of <size, ptr> for input */
  1928.     Proc_MigBuffer *outPtr;     /* pair of <size, ptr> for output */
  1929. {
  1930.     ReturnStatus status;
  1931.     Rpc_Storage storage;
  1932.     Proc_TraceRecord record;
  1933.     int maxSize;
  1934.     int toSend;
  1935.  
  1936. #ifndef CLEAN
  1937.     if (proc_DoTrace && proc_MigDebugLevel > 2) {
  1938.     record.processID = cmdPtr->remotePid;
  1939.     record.flags = PROC_MIGTRACE_START;
  1940.     record.info.command.type = cmdPtr->command;
  1941.     record.info.command.data = (ClientData) NIL;
  1942.     Trace_Insert(proc_TraceHdrPtr, PROC_MIGTRACE_COMMAND,
  1943.              (ClientData) &record);
  1944.     }
  1945. #endif /* CLEAN */   
  1946.  
  1947.     Rpc_MaxSizes(&maxSize, (int *) NIL);
  1948.  
  1949.     /*
  1950.      * Set up for the RPC.
  1951.      */
  1952.     storage.requestParamPtr = (Address) cmdPtr;
  1953.     storage.requestParamSize = sizeof(ProcMigCmd);
  1954.  
  1955.     if (inPtr == (Proc_MigBuffer *) NIL) {
  1956.     storage.requestDataPtr = (Address) NIL;
  1957.     storage.requestDataSize = 0;
  1958.     cmdPtr->totalSize = 0;
  1959.     toSend = 0;
  1960.     } else {
  1961.     toSend = inPtr->size;
  1962.     cmdPtr->totalSize = toSend;
  1963.     }
  1964.     cmdPtr->offset = 0;
  1965.  
  1966.     storage.replyParamPtr = (Address) NIL;
  1967.     storage.replyParamSize = 0;
  1968.  
  1969.     /*
  1970.      * Send the command, breaking it into sizes of at most size maxSize.
  1971.      * Only the last "fragment" can actually return any data.
  1972.      */
  1973.     do {
  1974.     if ((toSend > maxSize) || (outPtr == (Proc_MigBuffer *) NIL)) {
  1975.         storage.replyDataPtr = (Address) NIL;
  1976.         storage.replyDataSize = 0;
  1977.     } else {
  1978.         storage.replyDataPtr = outPtr->ptr;
  1979.         storage.replyDataSize = outPtr->size;
  1980.     }
  1981.     if (inPtr != (Proc_MigBuffer *) NIL) {
  1982.         storage.requestDataPtr = inPtr->ptr + cmdPtr->offset;
  1983.         storage.requestDataSize = (toSend > maxSize) ? maxSize : toSend;
  1984.     }
  1985.  
  1986.     if (proc_MigDebugLevel > 2) {
  1987.         printf("cmd %d totalSize %d offset %d thisDataSize %d\n",
  1988.            cmdPtr->command, cmdPtr->totalSize, cmdPtr->offset,
  1989.            storage.requestDataSize);
  1990.     }
  1991.  
  1992.     status = Rpc_Call(host, RPC_PROC_MIG_COMMAND, &storage);
  1993.  
  1994. #ifndef CLEAN
  1995.     if (proc_DoTrace && proc_MigDebugLevel > 2) {
  1996.         record.flags = 0;
  1997.         Trace_Insert(proc_TraceHdrPtr, PROC_MIGTRACE_COMMAND,
  1998.              (ClientData) &record);
  1999.     }
  2000. #endif                /* CLEAN */   
  2001.  
  2002.     if (status != SUCCESS) {
  2003.         if (proc_MigDebugLevel > 6) {
  2004.         printf("%s ProcMigCommand: error %x returned by Rpc_Call.\n",
  2005.                "Warning:", status);
  2006.         }
  2007.         return(status);
  2008.     }
  2009.     toSend -= maxSize;
  2010.     cmdPtr->offset += maxSize;
  2011.     } while (toSend > 0);
  2012.     return(SUCCESS);
  2013. }
  2014.  
  2015.  
  2016. /*
  2017.  *----------------------------------------------------------------------
  2018.  *
  2019.  * Proc_WaitForMigration --
  2020.  *
  2021.  *    Wait for a process to migrate.  Locks the process and
  2022.  *    then calls a monitored procedure.
  2023.  *    Note: this routine should not be used to verify that an arbitrary 
  2024.  *    process is migrated (RpcProcFork doesn't set PROC_MIGRATION_DONE).
  2025.  *
  2026.  * Results:
  2027.  *    Returns a Sprite status code.  SUCCESS means that the process has 
  2028.  *    context switched to PROC_MIGRATED.
  2029.  *
  2030.  * Side effects:
  2031.  *    None.
  2032.  *
  2033.  *----------------------------------------------------------------------
  2034.  */
  2035.  
  2036. ReturnStatus
  2037. Proc_WaitForMigration(processID)
  2038.     Proc_PID processID;
  2039. {
  2040.     Proc_ControlBlock *procPtr;
  2041.     ReturnStatus status;
  2042.  
  2043.     procPtr = Proc_LockPID(processID);
  2044.     if (procPtr == (Proc_ControlBlock *) NIL) {
  2045.     return(PROC_INVALID_PID);
  2046.     }
  2047.     /*
  2048.      * While in the middle of migration, wait on the condition
  2049.      * and then recheck the flags and the processID.
  2050.      * This avoids the possibility of the procPtr getting recycled while
  2051.      * we're waiting.
  2052.      */
  2053.     while (procPtr->genFlags & (PROC_MIG_PENDING | PROC_MIGRATING)) {
  2054.     Proc_Unlock(procPtr);
  2055.         status = WaitForMigration();
  2056.     if (status != SUCCESS) {
  2057.         return(status);
  2058.     }
  2059.     Proc_Lock(procPtr);
  2060.     if (procPtr->processID != processID) {
  2061.         Proc_Unlock(procPtr);
  2062.         return(PROC_INVALID_PID);
  2063.     }
  2064.     }
  2065.     if ((procPtr->genFlags & PROC_MIGRATION_DONE) &&
  2066.     (procPtr->state == PROC_MIGRATED)) {
  2067.     status = SUCCESS;
  2068.     } else {
  2069.     status = FAILURE;
  2070.     }
  2071.     Proc_Unlock(procPtr);
  2072.     
  2073.     return(status);
  2074. }
  2075.  
  2076.  
  2077. /*
  2078.  *----------------------------------------------------------------------
  2079.  *
  2080.  * WaitForMigration --
  2081.  *
  2082.  *    Monitored procedure to wait for a migration condition to be
  2083.  *    signalled.  Higher-level locking actually guarantees that
  2084.  *    a process has actually migrated.
  2085.  *
  2086.  * Results:
  2087.  *    SUCCESS, or GEN_ABORTED_BY_SIGNAL.    
  2088.  *
  2089.  * Side effects:
  2090.  *    Puts current process to sleep.
  2091.  *
  2092.  *----------------------------------------------------------------------
  2093.  */
  2094.  
  2095. static ENTRY ReturnStatus
  2096. WaitForMigration()
  2097. {
  2098.     ReturnStatus status;
  2099.     LOCK_MONITOR;
  2100.     if (Sync_Wait(&migrateCondition, TRUE)) {
  2101.         status = GEN_ABORTED_BY_SIGNAL;
  2102.     } else {
  2103.         status = SUCCESS;
  2104.     }
  2105.     UNLOCK_MONITOR;
  2106.     return(status);
  2107. }
  2108.  
  2109.  
  2110. /*
  2111.  *----------------------------------------------------------------------
  2112.  *
  2113.  * AddMigrateTime --
  2114.  *
  2115.  *    Monitored procedure to add a time to the statistics structure
  2116.  *    atomically.
  2117.  *
  2118.  * Results:
  2119.  *    None.
  2120.  *
  2121.  * Side effects:
  2122.  *    Adds time.
  2123.  *
  2124.  *----------------------------------------------------------------------
  2125.  */
  2126. static ENTRY void
  2127. AddMigrateTime(time, totalPtr, squaredTotalPtr)
  2128.     Time time;
  2129.     unsigned int *totalPtr;
  2130.     unsigned int *squaredTotalPtr;
  2131. {
  2132.     unsigned int intTime;
  2133.     unsigned int squaredTime;
  2134.  
  2135. #ifndef CLEAN
  2136.     LOCK_MONITOR;
  2137.  
  2138.     /*
  2139.      * Round times to hundreds of milliseconds, to keep things
  2140.      * on a low enough scale to keep from overflowing too easily.
  2141.      */
  2142.  
  2143.     intTime = PROC_MIG_TIME_FOR_STATS(time);
  2144.     *totalPtr += intTime;
  2145.     squaredTime = intTime * intTime;
  2146.     *squaredTotalPtr += squaredTime;
  2147.  
  2148.     UNLOCK_MONITOR;
  2149. #endif /* CLEAN */
  2150. }
  2151.  
  2152.  
  2153. /*
  2154.  *----------------------------------------------------------------------
  2155.  *
  2156.  * Proc_MigAddToCounter --
  2157.  *
  2158.  *    Monitored procedure to add a value to a global variable.
  2159.  *    This keeps statistics from being trashed if this were
  2160.  *    executed on a multiprocessor, since incrementing a counter
  2161.  *    isn't necessarily atomic.  If squaredPtr is non-NIL, it
  2162.  *    adds the square of the value to that variable.
  2163.  *
  2164.  * Results:
  2165.  *    None.
  2166.  *
  2167.  * Side effects:
  2168.  *    Updates variable pointed to by intPtr & squaredPtr.
  2169.  *
  2170.  *----------------------------------------------------------------------
  2171.  */
  2172. ENTRY void
  2173. Proc_MigAddToCounter(value, intPtr, squaredPtr)
  2174.     int value;
  2175.     unsigned int *intPtr;
  2176.     unsigned int *squaredPtr;
  2177. {
  2178.  
  2179.     LOCK_MONITOR;
  2180.  
  2181.     *intPtr += value;
  2182.     if (squaredPtr != (unsigned int *) NIL) {
  2183.     *squaredPtr += value * value;
  2184.     }
  2185.  
  2186.     UNLOCK_MONITOR;
  2187. }
  2188.  
  2189. /*
  2190.  *----------------------------------------------------------------------
  2191.  *
  2192.  * ProcRecordUsage --
  2193.  *
  2194.  *    Specialized procedure to update global CPU usages
  2195.  *    atomically.    Because we do some funny arithmetic to store
  2196.  *     the square of a time, we convert timer ticks into times and
  2197.  *     use the function defined above.
  2198.  *
  2199.  * Results:
  2200.  *    None.
  2201.  *
  2202.  * Side effects:
  2203.  *    Adds values.
  2204.  *
  2205.  *----------------------------------------------------------------------
  2206.  */
  2207. void
  2208. ProcRecordUsage(ticks, type)
  2209.     Timer_Ticks ticks;
  2210.     ProcRecordUsageType type;
  2211. {
  2212.     unsigned int *timePtr = (unsigned int *) NIL;
  2213.     unsigned int *squaredTimePtr = (unsigned int *) NIL;
  2214.     Time time;
  2215.  
  2216. #ifndef CLEAN
  2217.  
  2218.     if (type == PROC_MIG_USAGE_REMOTE_CPU) {
  2219.     timePtr = &proc_MigStats.varStats.remoteCPUTime;
  2220.     squaredTimePtr = &proc_MigStats.squared.remoteCPUTime;
  2221.     } else if (type == PROC_MIG_USAGE_TOTAL_CPU) {
  2222.     timePtr = &proc_MigStats.varStats.totalCPUTime;
  2223.     squaredTimePtr = &proc_MigStats.squared.totalCPUTime;
  2224.     proc_MigStats.processes++;
  2225.     } else if (type == PROC_MIG_USAGE_POST_EVICTION) {
  2226.     timePtr = &proc_MigStats.varStats.evictionCPUTime;
  2227.     squaredTimePtr = &proc_MigStats.squared.evictionCPUTime;
  2228.     proc_MigStats.evictionsToUs++;
  2229.     }
  2230.     Timer_TicksToTime(ticks, &time);
  2231.  
  2232.     AddMigrateTime(time, timePtr, squaredTimePtr);
  2233.  
  2234. #endif /* CLEAN */
  2235. }
  2236.  
  2237. /*
  2238.  *----------------------------------------------------------------------
  2239.  *
  2240.  * AccessStats --
  2241.  *
  2242.  *    Access the migration statistics structure atomically.  Individual
  2243.  *    fields may be incremented or decremented outside the lock, but
  2244.  *    looking at the whole structure synchronizes with actions that
  2245.  *    operate on double words, as does resetting it to 0.
  2246.  *
  2247.  *    If copyPtr is NIL, then reset the stats, else copy them.
  2248.  *
  2249.  * Results:
  2250.  *    If requested, a copy of the statistics structure is returned to
  2251.  *    the caller.
  2252.  *
  2253.  * Side effects:
  2254.  *    If requested, the statistics structure is zeroed.
  2255.  *
  2256.  *----------------------------------------------------------------------
  2257.  */
  2258. static ENTRY void
  2259. AccessStats(copyPtr)
  2260.     Proc_MigStats *copyPtr;  /* pointer to area to copy stats into, or NIL */
  2261. {    
  2262.  
  2263.     LOCK_MONITOR;
  2264.  
  2265.     if (copyPtr != (Proc_MigStats *) NIL) {
  2266.     bcopy((Address) &proc_MigStats, (Address) copyPtr,
  2267.           sizeof(Proc_MigStats));
  2268.     } else {
  2269.     bzero((Address) &proc_MigStats, sizeof(Proc_MigStats));
  2270.     proc_MigStats.statsVersion = statsVersion;
  2271.     }
  2272.     
  2273.     UNLOCK_MONITOR;
  2274. }
  2275.  
  2276. /*
  2277.  *----------------------------------------------------------------------
  2278.  *
  2279.  * Proc_MigGetStats --
  2280.  *
  2281.  *    Return migration statistics to the user.
  2282.  *
  2283.  * Results:
  2284.  *    SUCCESS, unless there's a problem copying to user space.
  2285.  *
  2286.  * Side effects:
  2287.  *    None.
  2288.  *
  2289.  *----------------------------------------------------------------------
  2290.  */
  2291. ReturnStatus
  2292. Proc_MigGetStats(addr)
  2293.     Address addr;
  2294. {
  2295.     Proc_MigStats copy;
  2296.     ReturnStatus status;
  2297.  
  2298.     AccessStats(©);
  2299.  
  2300.     status = Vm_CopyOut(sizeof(Proc_MigStats),
  2301.             (Address)©,
  2302.             addr);
  2303.     return(status);
  2304. }
  2305.  
  2306. /*
  2307.  *----------------------------------------------------------------------
  2308.  *
  2309.  * Proc_MigResetStats --
  2310.  *
  2311.  *    Zero the migration statistics structure.
  2312.  *
  2313.  * Results:
  2314.  *    SUCCESS.
  2315.  *
  2316.  * Side effects:
  2317.  *    None.
  2318.  *
  2319.  *----------------------------------------------------------------------
  2320.  */
  2321. ReturnStatus
  2322. Proc_MigResetStats()
  2323. {
  2324.  
  2325.     AccessStats((Proc_MigStats *) NIL);
  2326.     return(SUCCESS);
  2327. }
  2328.  
  2329. /*
  2330.  *----------------------------------------------------------------------
  2331.  *
  2332.  * ProcMigWakeupWaiters --
  2333.  *
  2334.  *    Monitored procedure to signal any processes that may have waited for
  2335.  *    a process to migrate.
  2336.  *
  2337.  * Results:
  2338.  *    None.
  2339.  *
  2340.  * Side effects:
  2341.  *    None.
  2342.  *
  2343.  *----------------------------------------------------------------------
  2344.  */
  2345. ENTRY void
  2346. ProcMigWakeupWaiters()
  2347. {
  2348.  
  2349.     LOCK_MONITOR;
  2350.  
  2351.     Sync_Broadcast(&migrateCondition);
  2352.  
  2353.     UNLOCK_MONITOR;
  2354. }
  2355.  
  2356.  
  2357. /*
  2358.  *----------------------------------------------------------------------
  2359.  *
  2360.  * Proc_MigrateStartTracing --
  2361.  *
  2362.  *    Initialize the tracing variables for process migration.
  2363.  *
  2364.  * Results:
  2365.  *    None.
  2366.  *
  2367.  * Side effects:
  2368.  *    None.
  2369.  *
  2370.  *----------------------------------------------------------------------
  2371.  */
  2372.  
  2373. void
  2374. Proc_MigrateStartTracing()
  2375. {
  2376.     static Boolean init = FALSE;
  2377.  
  2378.     if (!init) {
  2379.     init = TRUE;
  2380.     proc_TraceHdrPtr = &proc_TraceHeader;
  2381.     Trace_Init(proc_TraceHdrPtr, PROC_NUM_TRACE_RECS,
  2382.            sizeof(Proc_TraceRecord), 0);
  2383.     }
  2384.     proc_DoTrace = TRUE;
  2385. }
  2386.  
  2387.  
  2388.  
  2389. /*
  2390.  *----------------------------------------------------------------------
  2391.  *
  2392.  * Proc_DestroyMigratedProc --
  2393.  *
  2394.  *    Kill a process, presumably when its peer host (the home host
  2395.  *    of a foreign process, or the remote host of a migrated process)
  2396.  *    is down.  It may also be done if the process is
  2397.  *    unsuccessfully killed with a signal, even if the remote host
  2398.  *    hasn't been down long enough to be sure it has crashed.
  2399.  *
  2400.  *    This procedure is distinct from Proc_KillRemoteCopy, which issues
  2401.  *     a command to do a similar thing on the host to which the process
  2402.  *     is migrating.  In this case, we're killing our own copy of it.
  2403.  *
  2404.  * Results:
  2405.  *    None.
  2406.  *
  2407.  * Side effects:
  2408.  *    The process is killed.
  2409.  *
  2410.  *----------------------------------------------------------------------
  2411.  */
  2412.  
  2413. /* ARGSUSED */
  2414. void 
  2415. Proc_DestroyMigratedProc(pidData, callInfoPtr) 
  2416.     ClientData pidData;        /* the process ID, as a ClientData */
  2417.     Proc_CallInfo *callInfoPtr;         /* Not used. */
  2418. {
  2419.     Proc_ControlBlock         *procPtr; /* Process to kill. */
  2420.     Proc_PID pid = (Proc_PID) pidData;
  2421.  
  2422.     procPtr = Proc_LockPID(pid);
  2423.     if (procPtr == (Proc_ControlBlock *) NIL) {
  2424.     if (proc_MigDebugLevel > 0) {
  2425.         printf("Warning: Proc_DestroyMigratedProc: process %x not found.\n",
  2426.               (int) pid);
  2427.     }
  2428.     /*
  2429.      * Make sure the dependency on this process goes away.
  2430.      */
  2431.     ProcMigRemoveDependency(pid, TRUE);
  2432.     return;
  2433.     }
  2434.     if ((procPtr->state != PROC_MIGRATED) &&
  2435.     !(procPtr->genFlags & PROC_FOREIGN)) {
  2436.     if (procPtr->genFlags & PROC_MIGRATION_DONE) {
  2437.         /*
  2438.          * Just about to complete the migration.
  2439.          */
  2440.         procPtr->genFlags |= PROC_MIG_ERROR;
  2441.         if (proc_MigDebugLevel > 1) {
  2442.         printf("%s Proc_DestroyMigratedProc: process %x not done migrating.\n",
  2443.               "Warning:", (int) pid);
  2444.         }
  2445.  
  2446.     } else {
  2447.         if (proc_MigDebugLevel > 0) {
  2448.         printf("%s Proc_DestroyMigratedProc: process %x not migrated.\n",
  2449.               "Warning:", (int) pid);
  2450.         }
  2451.     }
  2452.     Proc_Unlock(procPtr);
  2453.     /*
  2454.      * Make sure the dependency on this process goes away.
  2455.      */
  2456.     ProcMigRemoveDependency(pid, TRUE);
  2457.     return;
  2458.     }
  2459.  
  2460.     if (procPtr->state == PROC_NEW && (procPtr->genFlags & PROC_FOREIGN)) {
  2461.     /*
  2462.      * The process was only partially migrated.
  2463.      */
  2464.     if (procPtr->remoteExecBuffer != (Address) NIL) {
  2465.         free(procPtr->remoteExecBuffer);
  2466.         procPtr->remoteExecBuffer = (Address) NIL;
  2467.     }
  2468.     procPtr->state = PROC_DEAD;
  2469.     Proc_CallFunc(Proc_Reaper, (ClientData) procPtr, 0);
  2470.     Proc_Unlock(procPtr);
  2471.     /*
  2472.      * Make sure the dependency on this process goes away.
  2473.      */
  2474.     ProcMigRemoveDependency(pid, TRUE);
  2475.     return;
  2476.     }    
  2477.     
  2478.     
  2479.     if (procPtr->state == PROC_MIGRATED) {
  2480.     /*
  2481.      * Perform an exit on behalf of the process -- it's not
  2482.      * in a state where we can signal it.  The process is
  2483.          * unlocked as a side effect.    We tell
  2484.      * the recovery system that it should try later on to
  2485.      * notify the other host since we aren't able to right now.
  2486.      */
  2487.     ProcExitProcess(procPtr, PROC_TERM_DESTROYED, (int) PROC_NO_PEER, 0,
  2488.             FALSE);
  2489.     ProcMigRemoveDependency(pid, FALSE);
  2490.     /*
  2491.      * Update statistics.
  2492.      */
  2493. #ifndef CLEAN
  2494.     if (proc_MigDoStats) {
  2495.         PROC_MIG_DEC_STAT(remote);
  2496.     }
  2497. #endif /* CLEAN */   
  2498.  
  2499.     } else {
  2500.     /*
  2501.      * Let it get killed the normal way, and let the exit routines
  2502.      * handle cleaning up dependencies.
  2503.      */
  2504.     Sig_SendProc(procPtr, SIG_KILL, (int) PROC_NO_PEER, (Address)0);
  2505.     Proc_Unlock(procPtr);
  2506.     }
  2507.  
  2508. }
  2509.  
  2510.  
  2511. /*
  2512.  *----------------------------------------------------------------------
  2513.  *
  2514.  * Proc_EvictForeignProcs --
  2515.  *
  2516.  *    Evict all foreign processes from this machine.  To do this, send
  2517.  *    each foreign process the SIG_MIGRATE_HOME signal.
  2518.  *
  2519.  * Results:
  2520.  *    If sending any signals returns a non-SUCCESS status, that status
  2521.  *    is returned.  Otherwise, SUCCESS is returned.
  2522.  *
  2523.  * Side effects:
  2524.  *    None.
  2525.  *
  2526.  *----------------------------------------------------------------------
  2527.  */
  2528.  
  2529. ReturnStatus
  2530. Proc_EvictForeignProcs()
  2531. {
  2532.     ReturnStatus status;
  2533.     int numEvicted;        /*  Not used */
  2534.  
  2535. #ifndef CLEAN
  2536.     if (proc_MigDoStats) {
  2537.     PROC_MIG_INC_STAT(evictCalls);
  2538.     }
  2539. #endif /* CLEAN */
  2540.     if (proc_MigStats.foreign == 0) {
  2541.     if (proc_MigDebugLevel > 2) {
  2542.         printf("Proc_EvictForeignProcs: no foreign processes.\n");
  2543.     }
  2544.     return(SUCCESS);
  2545.     }
  2546.     if (EvictionStarted()) {
  2547.     if (proc_MigDebugLevel > 0) {
  2548.         printf("Warning: eviction already in progress.\n");
  2549.     }
  2550.     /*
  2551.      * We really should wait for the previous one to complete and then
  2552.      * start over.  For now, just tell the user we couldn't do it.
  2553.      */
  2554.     return(FAILURE);
  2555.     }
  2556.     status = Proc_DoForEveryProc(Proc_IsEvictable, Proc_EvictProc, TRUE,
  2557.                   &numEvicted);
  2558.     Proc_MigAddToCounter(numEvicted, &proc_MigStats.varStats.evictions,
  2559.              &proc_MigStats.squared.evictions);
  2560.     WaitForEviction();
  2561.     return(status);
  2562. }
  2563.  
  2564.  
  2565. /*
  2566.  *----------------------------------------------------------------------
  2567.  *
  2568.  * Proc_IsEvictable --
  2569.  *
  2570.  *    Return whether the specified process is foreign and is okay
  2571.  *    to migrate.  (This routine is a callback procedure that may be 
  2572.  *    passed as a parameter to routines requiring an arbitrary
  2573.  *    Boolean procedure operating on a PCB.)
  2574.  *
  2575.  * Results:
  2576.  *    Boolean result: TRUE if foreign, FALSE if not.
  2577.  *
  2578.  * Side effects:
  2579.  *    None.
  2580.  *
  2581.  *----------------------------------------------------------------------
  2582.  */
  2583.  
  2584. Boolean
  2585. Proc_IsEvictable(procPtr)
  2586.     Proc_ControlBlock *procPtr;
  2587. {
  2588.     if ((procPtr->genFlags & PROC_FOREIGN) &&
  2589.     !(procPtr->genFlags & PROC_DONT_MIGRATE)) {
  2590.     return(TRUE);
  2591.     } else {
  2592.     return(FALSE);
  2593.     }
  2594. }
  2595.  
  2596.  
  2597. /*
  2598.  *----------------------------------------------------------------------
  2599.  *
  2600.  * Proc_EvictProc --
  2601.  *
  2602.  *    Send a process the SIG_MIGRATE_HOME signal.  Note that if
  2603.  *    the process is not foreign, then the signal will be ignored.
  2604.  *    (This routine is a callback procedure that may be passed as a
  2605.  *        parameter to routines requiring an arbitrary procedure
  2606.  *        operating on a Proc_PID and returning a ReturnStatus.)
  2607.  *
  2608.  * Results:
  2609.  *    The value from Sig_Send is returned.
  2610.  *
  2611.  * Side effects:
  2612.  *    The specified process is signalled.
  2613.  *
  2614.  *----------------------------------------------------------------------
  2615.  */
  2616.  
  2617. ReturnStatus
  2618. Proc_EvictProc(pid)
  2619.     Proc_PID pid;
  2620. {
  2621.     ReturnStatus status = SUCCESS;
  2622.     Proc_ControlBlock *procPtr;
  2623.     
  2624.  
  2625.     procPtr = Proc_LockPID(pid);
  2626.     if (procPtr == (Proc_ControlBlock *) NIL) {
  2627.     if (proc_MigDebugLevel > 2) {
  2628.         printf("Proc_EvictProc: process %x no longer exists.\n", pid);
  2629.     }
  2630.     return (PROC_INVALID_PID);
  2631.     }
  2632.     if (proc_MigDebugLevel > 2) {
  2633.     printf("Proc_EvictProc: evicting process %x.\n", pid);
  2634.     }
  2635.     if ((procPtr->genFlags & PROC_FOREIGN) &&
  2636.     !(procPtr->genFlags & (PROC_DONT_MIGRATE | PROC_DYING)) &&
  2637.     !(procPtr->migFlags & PROC_EVICTING)) {
  2638.     procPtr->migFlags |= PROC_EVICTING;
  2639.     PROC_MIG_INC_STAT(evictionsInProgress);
  2640.     status = Sig_SendProc(procPtr, SIG_MIGRATE_HOME, 0, (Address)0);
  2641.     }
  2642.     Proc_Unlock(procPtr);
  2643.     return(status); 
  2644. }
  2645.  
  2646.  
  2647. /*
  2648.  *----------------------------------------------------------------------
  2649.  *
  2650.  * EvictionStarted --
  2651.  *
  2652.  *    Monitored procedure to initialize variables for recording
  2653.  *    eviction times.
  2654.  *
  2655.  * Results:
  2656.  *    TRUE if an eviction was already in progress, else FALSE.
  2657.  *
  2658.  * Side effects:
  2659.  *    The file-global evictionStarted time variable is initialized.
  2660.  *
  2661.  *----------------------------------------------------------------------
  2662.  */
  2663.  
  2664. static ENTRY Boolean
  2665. EvictionStarted()
  2666. {
  2667.     LOCK_MONITOR;
  2668.  
  2669.     if (proc_MigStats.evictionsInProgress != 0) {
  2670.     UNLOCK_MONITOR;
  2671.     return(TRUE);
  2672.     }
  2673. #ifndef CLEAN
  2674.     if (proc_MigDoStats) {
  2675.     Timer_GetTimeOfDay(&timeEvictionStarted, (int *) NIL, (Boolean *) NIL);
  2676.     }
  2677. #endif /* CLEAN */
  2678.     
  2679.     UNLOCK_MONITOR;
  2680.     return(FALSE);
  2681. }
  2682.  
  2683. /*
  2684.  *----------------------------------------------------------------------
  2685.  *
  2686.  * WaitForEviction --
  2687.  *
  2688.  *    Monitored procedure to record eviction times after eviction has
  2689.  *    completed.  
  2690.  *
  2691.  * Results:
  2692.  *    None.
  2693.  *
  2694.  * Side effects:
  2695.  *    The time taken for eviction is added to the statistics structure.
  2696.  *
  2697.  *----------------------------------------------------------------------
  2698.  */
  2699.  
  2700. static ENTRY void
  2701. WaitForEviction()
  2702. {
  2703.     Time time;
  2704.  
  2705.     LOCK_MONITOR;
  2706.  
  2707.     if (proc_MigStats.evictionsInProgress == 0) {
  2708.     UNLOCK_MONITOR;
  2709.     return;
  2710.     }
  2711.     while (proc_MigStats.evictionsInProgress != 0) {
  2712.     if (Sync_Wait(&evictCondition, TRUE)) {
  2713.         /*
  2714.          * Interrupted.  Just give up.
  2715.          */
  2716.         proc_MigStats.evictionsInProgress = 0;
  2717.         UNLOCK_MONITOR;
  2718.         return;
  2719.     }
  2720.     }
  2721. #ifndef CLEAN
  2722.     if (proc_MigDoStats) {
  2723.     int intTime;
  2724.     int squaredTime;
  2725.  
  2726.     Timer_GetTimeOfDay(&time, (int *) NIL, (Boolean *) NIL);
  2727.     Time_Subtract(time, timeEvictionStarted, &time);
  2728.     intTime = PROC_MIG_TIME_FOR_STATS(time);
  2729.     squaredTime = intTime * intTime;
  2730.     proc_MigStats.varStats.totalEvictTime += intTime;
  2731.     proc_MigStats.squared.totalEvictTime += squaredTime;
  2732.  
  2733.     proc_MigStats.evictsNeeded++;
  2734.     }
  2735. #endif /* CLEAN */   
  2736.     UNLOCK_MONITOR;
  2737. }
  2738.  
  2739. /*
  2740.  *----------------------------------------------------------------------
  2741.  *
  2742.  * ProcMigEvictionComplete --
  2743.  *
  2744.  *    Monitored procedure to signal the process that is recording eviction
  2745.  *    statistics.  This is done any time an eviction completes. When
  2746.  *    the count of evictions hits zero, we wake up the process waiting for
  2747.  *     eviction.  If the count of foreign processes ever hits 0 we also
  2748.  *     know all evictions are complete -- this is a double-check against
  2749.  *    losing track of a process during eviction if something unexpected
  2750.  *    happens (such as if it gets "destroyed").
  2751.  *
  2752.  * Results:
  2753.  *    None.
  2754.  *
  2755.  * Side effects:
  2756.  *    Notifies waiting process.
  2757.  *
  2758.  *----------------------------------------------------------------------
  2759.  */
  2760. ENTRY void
  2761. ProcMigEvictionComplete()
  2762. {
  2763.  
  2764.     LOCK_MONITOR;
  2765.  
  2766.     if (proc_MigStats.foreign == 0) {
  2767.     proc_MigStats.evictionsInProgress = 0;
  2768.     } else if (proc_MigStats.evictionsInProgress != 0) {
  2769.     proc_MigStats.evictionsInProgress--;
  2770.     }
  2771.     if (proc_MigStats.evictionsInProgress == 0) {
  2772.     Sync_Broadcast(&evictCondition);
  2773.     }
  2774.  
  2775.     UNLOCK_MONITOR;
  2776. }
  2777.  
  2778. /*
  2779.  *----------------------------------------------------------------------
  2780.  *
  2781.  * Proc_NeverMigrate --
  2782.  *
  2783.  *    Flag a process so it will never be migrated.  This may be
  2784.  *     used to keep the master of a pseudo-device from migrating, or
  2785.  *     a process with kernel addresses mapped into user space from
  2786.  *    migrating.  The process is flagged as unmigrateable for the rest of
  2787.  *     the lifetime of the process.
  2788.  *
  2789.  * Results:
  2790.  *    None.
  2791.  *
  2792.  * Side effects:
  2793.  *    The process's genFlags field is modified.
  2794.  *
  2795.  *----------------------------------------------------------------------
  2796.  */
  2797.  
  2798. void
  2799. Proc_NeverMigrate(procPtr)
  2800.     Proc_ControlBlock *procPtr;
  2801. {
  2802.  
  2803.     Proc_Lock(procPtr);
  2804.     if (proc_MigDebugLevel > 4) {
  2805.     printf("Proc_NeverMigrate: don't migrate process %x.\n",
  2806.            procPtr->processID);
  2807.     }
  2808.     if (!(procPtr->genFlags & PROC_DONT_MIGRATE)) {
  2809.     procPtr->genFlags |= PROC_DONT_MIGRATE;
  2810.     if (procPtr->genFlags & PROC_FOREIGN) {
  2811.         if (proc_MigDebugLevel > 3) {
  2812.         printf("Proc_NeverMigrate: process %x is foreign.\n",
  2813.                procPtr->processID);
  2814.         }
  2815.         PROC_MIG_DEC_STAT(foreign);
  2816.     }
  2817.     }
  2818.     Proc_Unlock(procPtr);
  2819. }
  2820.  
  2821.  
  2822. /*
  2823.  *----------------------------------------------------------------------
  2824.  *
  2825.  * Proc_GetEffectiveProc --
  2826.  *
  2827.  *    Get a pointer to the Proc_ControlBlock for the process that is
  2828.  *    *effectively* running on the current processor.  Thus, for an
  2829.  *    RPC server performing a system call on behalf of a migrated process,
  2830.  *    the "effective" process will be the process that invoked the system
  2831.  *    call.  In all other cases, the "effective" process will be the
  2832.  *    same as the "actual" process.
  2833.  *
  2834.  * Results:
  2835.  *    A pointer to the process is returned.  If no process is active,
  2836.  *    NIL is returned.
  2837.  *
  2838.  * Side effects:
  2839.  *    None.
  2840.  *
  2841.  *----------------------------------------------------------------------
  2842.  */
  2843. Proc_ControlBlock *
  2844. Proc_GetEffectiveProc()
  2845. {
  2846.     Proc_ControlBlock *procPtr;
  2847.  
  2848.     procPtr = proc_RunningProcesses[Mach_GetProcessorNumber()];
  2849.     if (procPtr == (Proc_ControlBlock *) NIL ||
  2850.         procPtr->rpcClientProcess ==  (Proc_ControlBlock *) NIL) {
  2851.     return(procPtr);
  2852.     }
  2853.     return(procPtr->rpcClientProcess);
  2854. }
  2855.  
  2856.  
  2857. /*
  2858.  *----------------------------------------------------------------------
  2859.  *
  2860.  * Proc_SetEffectiveProc --
  2861.  *
  2862.  *    Set the "effective" process on the current processor.  If the
  2863.  *    process is (Proc_ControlBlock) NIL, the effective process is
  2864.  *    the same as the real process.
  2865.  *
  2866.  * Results:
  2867.  *    None.  
  2868.  *
  2869.  * Side effects:
  2870.  *    The "rpcClientProcess" field of the current process's
  2871.  *    Proc_ControlBlock is set to hold the effective process.
  2872.  *
  2873.  *----------------------------------------------------------------------
  2874.  */
  2875. void
  2876. Proc_SetEffectiveProc(procPtr)
  2877.     Proc_ControlBlock *procPtr;
  2878. {
  2879.     Proc_ControlBlock *actualProcPtr;
  2880.  
  2881.     actualProcPtr = Proc_GetActualProc();
  2882.     if (actualProcPtr == (Proc_ControlBlock *) NIL) {
  2883.     panic("Proc_SetEffectiveProcess: current process is NIL.\n");
  2884.     } else {
  2885.     actualProcPtr->rpcClientProcess = procPtr;
  2886.     }
  2887. }
  2888.  
  2889.